1 package modify
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "time"
8
9 "edge-infra.dev/pkg/edge/api/graph/model"
10 "edge-infra.dev/pkg/edge/constants"
11 "edge-infra.dev/pkg/edge/edgecli"
12 "edge-infra.dev/pkg/edge/edgecli/constructors"
13 "edge-infra.dev/pkg/edge/edgecli/flagutil"
14 "edge-infra.dev/pkg/lib/cli/command"
15 "edge-infra.dev/pkg/lib/cli/rags"
16 "edge-infra.dev/pkg/lib/networkvalidator"
17 )
18
19 var (
20 networkAddressValidationMap = map[string]struct {
21 validateFunc func(string) bool
22 inetType string
23 errorFormat string
24 }{
25 flagutil.IPv4Flag: {
26 validateFunc: func(ip string) bool {
27 return networkvalidator.IsValidDomain(ip) || networkvalidator.ValidateIP(ip)
28 },
29 inetType: "inet",
30 errorFormat: "invalid IPv4 address or domain %s",
31 },
32 flagutil.IPv6Flag: {
33 validateFunc: func(ip string) bool {
34 return networkvalidator.IsValidDomain(ip) || networkvalidator.ValidateIP(ip)
35 },
36 inetType: "inet6",
37 errorFormat: "invalid IPv6 address or domain %s",
38 },
39 flagutil.CIDRFlag: {
40 validateFunc: networkvalidator.IsValidCIDR,
41 inetType: "inet",
42 errorFormat: "invalid CIDR range %s",
43 },
44 }
45 )
46
47 func NewCmd(cfg *edgecli.Config) *command.Command {
48 var cmd *command.Command
49 flagsets := flagutil.GetConnectionFlags(cfg)
50 var storeName, bannerName, networkServiceID string
51
52 cmd = &command.Command{
53 ShortUsage: "edge networkservice modify",
54 ShortHelp: "Modify a Network Service belonging to a Cluster",
55 Flags: append(
56 flagsets,
57 &rags.Rag{
58 Name: flagutil.StoreFlag,
59 Usage: "Name of the Store",
60 Value: &rags.String{Var: &storeName},
61 Required: true,
62 },
63 &rags.Rag{
64 Name: flagutil.BannerFlag,
65 Usage: "Banner name",
66 Value: &rags.String{Var: &bannerName},
67 Required: true,
68 },
69
70 &rags.Rag{
71 Name: flagutil.IPv4Flag,
72 Usage: "IPv4 address of service",
73 Value: &rags.String{},
74 Required: false,
75 },
76 &rags.Rag{
77 Name: flagutil.IPv6Flag,
78 Usage: "IPv6 address of service",
79 Value: &rags.String{},
80 Required: false,
81 },
82 &rags.Rag{
83 Name: flagutil.CIDRFlag,
84 Usage: "CIDR range of service",
85 Value: &rags.String{},
86 Required: false,
87 },
88 &rags.Rag{
89 Name: flagutil.NetworkServiceIDFlag,
90 Value: &rags.String{Var: &networkServiceID},
91 Usage: "ID of network service",
92 Required: true,
93 },
94 &rags.Rag{
95 Name: flagutil.Priority,
96 Usage: "Priority of the network service (must be a positive int)",
97 Required: false,
98 Value: &rags.Int{Default: 100},
99 },
100 ),
101 Exec: func(_ context.Context, _ []string) error {
102 if err := flagutil.ValidateRequiredFlags(cmd.Rags); err != nil {
103 return err
104 }
105
106 registrar, err := constructors.BuildRegistrar(cmd.Rags)
107 if err != nil {
108 return err
109 }
110
111
112
113
114
115 var passedFlags []string
116
117
118 if flagutil.GetStringFlag(cmd.Rags, flagutil.IPv4Flag) != "" {
119 passedFlags = append(passedFlags, flagutil.IPv4Flag)
120 }
121
122
123 if flagutil.GetStringFlag(cmd.Rags, flagutil.IPv6Flag) != "" {
124 passedFlags = append(passedFlags, flagutil.IPv6Flag)
125 }
126
127
128 if flagutil.GetStringFlag(cmd.Rags, flagutil.CIDRFlag) != "" {
129 passedFlags = append(passedFlags, flagutil.CIDRFlag)
130 }
131
132 if len(passedFlags) != 1 {
133 return errors.New("must pass exactly one of --ipv4, --ipv6, --cidr")
134 }
135
136 flag := passedFlags[0]
137
138 networkServiceID := flagutil.GetStringFlag(cmd.Rags, flagutil.NetworkServiceIDFlag)
139 storeName := flagutil.GetStringFlag(cmd.Rags, flagutil.StoreFlag)
140 bannerName := flagutil.GetStringFlag(cmd.Rags, flagutil.BannerFlag)
141
142 reqCtx, cancelReq := context.WithTimeout(context.Background(), time.Duration(30)*time.Second)
143 defer cancelReq()
144
145 cluster, err := registrar.GetCluster(reqCtx, storeName, bannerName)
146 if err != nil {
147 fmt.Println("an error occurred whilst modifying the cluster network service")
148 return err
149 }
150
151 var serviceType string
152 for _, netService := range cluster.ClusterNetworkServices {
153 if netService.NetworkServiceID == networkServiceID {
154 serviceType = netService.ServiceType
155 break
156 }
157 }
158 if serviceType == "" {
159 return errors.New("the networkServiceID provided does not exist in this cluster")
160 }
161 if serviceType == constants.ServiceTypeClusterDNS {
162 return fmt.Errorf("%s is not directly configurable - update %s instead", constants.ServiceTypeClusterDNS, constants.ServiceTypeServiceNetworkCIDR)
163 }
164
165 ipAddress, ipFamily, err := validateNetworkAddress(cmd.Rags, flag, serviceType)
166 if err != nil {
167 return err
168 }
169
170 netService := model.UpdateNetworkServiceInfo{}
171
172 if flagutil.GetBoolFlag(cmd.Rags, flagutil.Priority) {
173 priority := flagutil.GetIntFlag(cmd.Rags, flagutil.Priority)
174 netService.Priority = &priority
175 }
176 netService.NetworkServiceID = networkServiceID
177 netService.IP = ipAddress
178 netService.Family = ipFamily
179
180
181
182 networkServices := []model.UpdateNetworkServiceInfo{
183 netService,
184 }
185
186 fmt.Println("modifying network services...")
187
188 reqCtx, cancelReq = context.WithTimeout(context.Background(), time.Duration(30)*time.Second)
189 defer cancelReq()
190
191 if _, err = registrar.ModifyNetworkServices(reqCtx, cluster.ClusterEdgeID, networkServices); err != nil {
192 fmt.Println("an error occurred whilst modifying network services")
193 return err
194 }
195
196 fmt.Println("network services modified successfully!")
197 return nil
198 },
199 }
200 return cmd
201 }
202
203 func validateNetworkAddress(rs *rags.RagSet, flag string, serviceType string) (string, string, error) {
204 switch serviceType {
205 case constants.ServiceTypePodNetworkCIDR, constants.ServiceTypeServiceNetworkCIDR:
206 if flag == flagutil.IPv4Flag || flag == flagutil.IPv6Flag {
207 fmt.Println(flag)
208 return "", "", fmt.Errorf("k8s network services must be CIDR ranges - use --cidr not --ipv4/--ipv6")
209 }
210 default:
211 if flag == flagutil.CIDRFlag {
212 fmt.Println(flag)
213 return "", "", fmt.Errorf("only k8s network services should be CIDR ranges - use --ipv4 or --ipv6, not --cidr")
214 }
215 }
216
217 ipAddress := flagutil.GetStringFlag(rs, flag)
218
219 if validation, ok := networkAddressValidationMap[flag]; ok {
220 if !validation.validateFunc(ipAddress) {
221 return "", "", fmt.Errorf(validation.errorFormat, ipAddress)
222 }
223 return ipAddress, validation.inetType, nil
224 }
225
226 return "", "", fmt.Errorf("couldn't validate unknown flag %s", flag)
227 }
228
View as plain text