1 package integration_test
2
3 import (
4 "context"
5 "strings"
6
7 "github.com/udacity/graphb"
8
9 "edge-infra.dev/pkg/edge/api/graph/model"
10 testApi "edge-infra.dev/pkg/edge/api/graph/test"
11 "edge-infra.dev/pkg/edge/api/services"
12 "edge-infra.dev/pkg/edge/api/types"
13 "edge-infra.dev/pkg/edge/api/utils"
14 "edge-infra.dev/pkg/edge/constants/api/cluster"
15 "edge-infra.dev/pkg/edge/constants/api/fleet"
16 "edge-infra.dev/pkg/lib/runtime/version"
17 "edge-infra.dev/test/framework/integration"
18 )
19
20 func (s *Suite) TestRegisterCluster() {
21 integration.SkipIf(s.Framework)
22 createSite := true
23 var response struct{ RegisterCluster *model.RegistrationResponse }
24 mutation := registerClusterMutation(&model.RegistrationPayload{
25 Name: testStore,
26 Fleet: fleet.Store,
27 ClusterType: cluster.GKE,
28 StoreInfo: &model.StoreInfo{
29 StoreID: &testStoreID,
30 CreateSite: &createSite,
31 },
32 BannerName: testOrg,
33 ClusterInfo: &model.ClusterInfo{
34 Location: testLocation,
35 NodeVersion: &testClusterVersion,
36 MachineType: testClusterMachineType,
37 NumNodes: testClusterNumNodes,
38 },
39 })
40 ResolverClient.MustPost(mutation, &response)
41 s.NotNil(response.RegisterCluster)
42 s.NotEmpty(response.RegisterCluster.ClusterEdgeID)
43 s.Equal(*response.RegisterCluster.SiteID, testSiteID)
44 }
45
46 func (s *Suite) TestRegisterDSDSCluster() {
47 store := "dsds-cluster"
48 testDSDSCluster(s, store, cluster.DSDS)
49 }
50
51 func testDSDSCluster(s *Suite, store, clusterProvider string) {
52 integration.SkipIf(s.Framework)
53 createSite := true
54 var response struct{ RegisterCluster *model.RegistrationResponse }
55 mutation := registerClusterMutation(&model.RegistrationPayload{
56 Name: store,
57 Fleet: fleet.Store,
58 ClusterType: clusterProvider,
59 StoreInfo: &model.StoreInfo{
60 StoreID: &testStoreID,
61 CreateSite: &createSite,
62 },
63 BannerName: testOrg,
64 ClusterInfo: &model.ClusterInfo{
65 Location: testLocation,
66 NodeVersion: &testClusterVersion,
67 MachineType: testClusterMachineType,
68 NumNodes: testClusterNumNodes,
69 },
70 })
71 err := ResolverClient.Post(mutation, &response)
72 s.NoError(err)
73 s.NotNil(response)
74 s.NotNil(response.RegisterCluster)
75 s.NotEmpty(response.RegisterCluster.ClusterEdgeID)
76 s.Equal(*response.RegisterCluster.SiteID, testSiteID)
77
78 clusterEdgeID := response.RegisterCluster.ClusterEdgeID
79 var clusterConfigResponse struct{ ClusterConfig *model.ClusterConfig }
80 query := getClusterConfigQuery(clusterEdgeID)
81 err = ResolverClient.Post(query, &clusterConfigResponse)
82 s.NoError(err)
83 s.NotNil(clusterConfigResponse)
84 s.NotNil(clusterConfigResponse.ClusterConfig)
85 s.Equal(model.ClusterConfig{
86 ClusterEdgeID: clusterEdgeID,
87 AcRelay: false,
88 VpnEnabled: false,
89 BootstrapAck: true,
90 PxeEnabled: false,
91 ThickPos: true,
92 EgressGatewayEnabled: false,
93 }, *clusterConfigResponse.ClusterConfig)
94 }
95
96 func (s *Suite) TestRegisterClusterByBannerEdgeID() {
97 integration.SkipIf(s.Framework)
98 createSite := true
99 var response struct{ RegisterCluster *model.RegistrationResponse }
100 mutation := registerClusterMutation(&model.RegistrationPayload{
101 Name: "banner_edge_id_store",
102 Fleet: fleet.Store,
103 ClusterType: cluster.GKE,
104 StoreInfo: &model.StoreInfo{
105 StoreID: &testStoreID,
106 CreateSite: &createSite,
107 },
108 BannerName: testOrg,
109 BannerEdgeID: &testApi.TestOrgEdgeID,
110 ClusterInfo: &model.ClusterInfo{
111 Location: testLocation,
112 NodeVersion: &testClusterVersion,
113 MachineType: testClusterMachineType,
114 NumNodes: testClusterNumNodes,
115 },
116 })
117 ResolverClient.MustPost(mutation, &response)
118 s.NotNil(response.RegisterCluster)
119 s.NotEmpty(response.RegisterCluster.ClusterEdgeID)
120 s.Equal(*response.RegisterCluster.SiteID, testSiteID)
121 }
122
123 func (s *Suite) TestRegisterExistingCluster() {
124 integration.SkipIf(s.Framework)
125 createSite := true
126 var response struct{ RegisterCluster *model.RegistrationResponse }
127 mutation := registerClusterMutation(&model.RegistrationPayload{
128 Name: "test_cluster-status",
129 Fleet: fleet.Store,
130 ClusterType: cluster.GKE,
131 StoreInfo: &model.StoreInfo{
132 StoreID: &testStoreID,
133 CreateSite: &createSite,
134 },
135 BannerName: "store-status-banner",
136 ClusterInfo: &model.ClusterInfo{
137 Location: testLocation,
138 NodeVersion: &testClusterVersion,
139 MachineType: testClusterMachineType,
140 NumNodes: testClusterNumNodes,
141 },
142 })
143 err := ResolverClient.Post(mutation, &response)
144 s.Error(err)
145 s.ErrorContains(err, "[{\"message\":\"cluster already registered, please try again with a different name. cluster name: test_cluster-status\",\"path\":[\"registerCluster\"]}]")
146 }
147
148 func (s *Suite) TestRegister_ReuseClusterName() {
149 integration.SkipIf(s.Framework)
150 createSite := true
151 request := &model.RegistrationPayload{
152 Name: "test-register-reuse-name",
153 Fleet: fleet.Store,
154 ClusterType: cluster.DSDS,
155 StoreInfo: &model.StoreInfo{
156 StoreID: &testStoreID,
157 CreateSite: &createSite,
158 },
159 BannerName: testOrg,
160 BannerEdgeID: &testApi.TestOrgEdgeID,
161 ClusterInfo: &model.ClusterInfo{
162 Location: testLocation,
163 NodeVersion: &testClusterVersion,
164 MachineType: testClusterMachineType,
165 NumNodes: testClusterNumNodes,
166 },
167 }
168
169
170 var response1 struct{ RegisterCluster *model.RegistrationResponse }
171 s.NoError(
172 ResolverClient.Post(registerClusterMutation(request), &response1),
173 "unexpected error registering cluster. first registration with unique name should succeed",
174 )
175 clusterID1 := response1.RegisterCluster.ClusterEdgeID
176
177
178 var response2 struct{ RegisterCluster *model.RegistrationResponse }
179 s.Error(
180 ResolverClient.Post(registerClusterMutation(request), &response2),
181 "error registering cluster. second registration with same name should fail",
182 )
183 s.Equal(clusterID1, response2.RegisterCluster.ClusterEdgeID, "expected registration response to return id of existing cluster")
184
185
186 var deleteResponse struct{ DeleteCluster *bool }
187 s.NoError(
188 ResolverClient.Post(deleteClusterQuery(clusterID1, false), &deleteResponse),
189 "unexpected error deleting cluster",
190 )
191 s.Require().NotNil(deleteResponse.DeleteCluster, "expected deleteCluster to return true, was nil")
192 s.True(*deleteResponse.DeleteCluster, "expected deleteCluster to return true")
193
194
195 var response3 struct{ RegisterCluster *model.RegistrationResponse }
196 s.NoError(
197 ResolverClient.Post(registerClusterMutation(request), &response3),
198 "unexpected error registering cluster. registration should succeed when reusing deleted cluster name",
199 )
200 clusterID3 := response3.RegisterCluster.ClusterEdgeID
201
202 s.NotEqual(clusterID1, clusterID3, "cluster_edge_ids should differ when reusing old cluster name for new registration")
203 }
204
205 func (s *Suite) TestRegisterClusterCreateSQLEntryError() {
206 integration.SkipIf(s.Framework)
207 createSite := true
208 var response struct{ RegisterCluster *model.RegistrationResponse }
209 mutation := registerClusterMutation(&model.RegistrationPayload{
210 Name: "test-store-2",
211 Fleet: fleet.Store,
212 ClusterType: "unknown type",
213 StoreInfo: &model.StoreInfo{
214 StoreID: &testStoreID,
215 CreateSite: &createSite,
216 },
217 BannerName: testOrg,
218 ClusterInfo: &model.ClusterInfo{
219 Location: testLocation,
220 NodeVersion: &testClusterVersion,
221 MachineType: testClusterMachineType,
222 NumNodes: testClusterNumNodes,
223 },
224 })
225 err := ResolverClient.Post(mutation, &response)
226 s.Error(err)
227 s.False(strings.Contains(err.Error(), "rollback errors"))
228
229
230 createSite = true
231 mutation = registerClusterMutation(&model.RegistrationPayload{
232 Name: "test-store-2",
233 Fleet: fleet.Store,
234 ClusterType: cluster.GKE,
235 StoreInfo: &model.StoreInfo{
236 StoreID: &testStoreID,
237 CreateSite: &createSite,
238 },
239 BannerName: testOrg,
240 ClusterInfo: &model.ClusterInfo{
241 Location: testLocation,
242 NodeVersion: &testClusterVersion,
243 MachineType: testClusterMachineType,
244 NumNodes: testClusterNumNodes,
245 },
246 })
247 ResolverClient.MustPost(mutation, &response)
248 s.NotNil(response.RegisterCluster)
249 s.NotEmpty(response.RegisterCluster.ClusterEdgeID)
250 s.Equal(*response.RegisterCluster.SiteID, testSiteID)
251 }
252
253 func (s *Suite) TestRegisterClusterCreateBanner() {
254 integration.SkipIf(s.Framework)
255 createSite := false
256 var response struct{ RegisterCluster *model.RegistrationResponse }
257 mutation := registerClusterMutation(&model.RegistrationPayload{
258 Name: "test-store-3",
259 Fleet: fleet.Cluster,
260 ClusterType: cluster.GKE,
261 StoreInfo: &model.StoreInfo{
262 StoreID: &testStoreID,
263 CreateSite: &createSite,
264 },
265 BannerName: testOrg,
266 ClusterInfo: &model.ClusterInfo{
267 Location: testLocation,
268 NodeVersion: &testClusterVersion,
269 MachineType: testClusterMachineType,
270 NumNodes: testClusterNumNodes,
271 },
272 })
273 err := ResolverClient.Post(mutation, &response)
274 s.NoError(err)
275 s.NotNil(response.RegisterCluster)
276 s.NotEmpty(response.RegisterCluster.ClusterEdgeID)
277 s.Equal(*response.RegisterCluster.SiteID, "")
278 }
279
280 func (s *Suite) TestRegisterCluster_AutoUpdateBackCompat() {
281 integration.SkipIf(s.Framework)
282 createSite := false
283 var response struct{ RegisterCluster *model.RegistrationResponse }
284 latest := types.DefaultVersionTag
285 mutation := registerClusterMutation(&model.RegistrationPayload{
286 Name: "test-store-4",
287 Fleet: fleet.Store,
288 FleetVersion: &latest,
289 ClusterType: cluster.Generic,
290 StoreInfo: &model.StoreInfo{
291 StoreID: &testStoreID,
292 CreateSite: &createSite,
293 },
294 BannerName: testOrg,
295 ClusterInfo: &model.ClusterInfo{
296 Location: testLocation,
297 NodeVersion: &testClusterVersion,
298 MachineType: testClusterMachineType,
299 NumNodes: testClusterNumNodes,
300 },
301 })
302 err := ResolverClient.Post(mutation, &response)
303 s.NoError(err)
304 s.NotNil(response.RegisterCluster)
305
306 newClusterQuery := graphb.Query{
307 Type: graphb.TypeQuery,
308 Fields: []*graphb.Field{
309 {
310 Name: "cluster",
311 Arguments: []graphb.Argument{
312 graphb.ArgumentString("clusterEdgeId", response.RegisterCluster.ClusterEdgeID),
313 },
314 Fields: []*graphb.Field{
315 graphb.NewField("fleetVersion"),
316 },
317 },
318 },
319 }
320 var clusterResponse struct{ Cluster *model.Cluster }
321 s.NoError(ResolverClient.Post(MustParse(newClusterQuery), &clusterResponse))
322 s.NotNil(clusterResponse.Cluster)
323 s.Equal(version.New().SemVer, clusterResponse.Cluster.FleetVersion)
324 }
325
326 func registerClusterMutation(payload *model.RegistrationPayload) string {
327 if payload.FleetVersion == nil {
328 version := types.DefaultVersionTag
329 payload.FleetVersion = &version
330 }
331 if payload.AutoUpdateEnabled == nil {
332 autoUpdate := false
333 payload.AutoUpdateEnabled = &autoUpdate
334 }
335 return MustParse(graphb.Query{
336 Type: graphb.TypeMutation,
337 Fields: []*graphb.Field{
338 {
339 Name: "registerCluster",
340 Arguments: []graphb.Argument{
341 graphb.ArgumentCustomType("payload",
342 graphb.ArgumentString("name", payload.Name),
343 graphb.ArgumentString("fleet", payload.Fleet),
344 graphb.ArgumentString("fleetVersion", *payload.FleetVersion),
345 graphb.ArgumentBool("autoUpdateEnabled", *payload.AutoUpdateEnabled),
346 graphb.ArgumentString("clusterType", payload.ClusterType),
347 graphb.ArgumentString("bannerName", payload.BannerName),
348 graphb.ArgumentCustomType("clusterInfo",
349 graphb.ArgumentString("location", payload.ClusterInfo.Location),
350 graphb.ArgumentString("machineType", payload.ClusterInfo.MachineType),
351 graphb.ArgumentString("nodeVersion", *payload.ClusterInfo.NodeVersion),
352 graphb.ArgumentInt("numNodes", payload.ClusterInfo.NumNodes),
353 graphb.ArgumentBool("autoscale", payload.ClusterInfo.Autoscale),
354 graphb.ArgumentInt("minNodes", utils.ConvertToInt(payload.ClusterInfo.MinNodes)),
355 graphb.ArgumentInt("maxNodes", utils.ConvertToInt(payload.ClusterInfo.MaxNodes)),
356 ),
357 graphb.ArgumentCustomType("storeInfo",
358 graphb.ArgumentString("storeID", *payload.StoreInfo.StoreID),
359 graphb.ArgumentBool("createSite", *payload.StoreInfo.CreateSite),
360 ),
361 ),
362 },
363 Fields: graphb.Fields("clusterEdgeId", "siteId"),
364 },
365 },
366 })
367 }
368
369 const (
370
371 resetClusterEdgeID = "076b3f30-7c78-4b19-9d43-f8f476ab0d58"
372 )
373
374 func (s *Suite) TestResetStoreClusterForce() {
375 integration.SkipIf(s.Framework)
376
377 var response struct{ ResetCluster bool }
378 mutation := resetClusterMutation(resetClusterEdgeID, true)
379 err := ResolverClient.Post(mutation, &response)
380 s.NoError(err)
381 cluster, err := s.Resolver.StoreClusterService.GetCluster(context.Background(), resetClusterEdgeID)
382 s.NoError(err)
383 s.NotNil(cluster.Active)
384 s.False(*cluster.Active)
385 }
386
387 func (s *Suite) TestResetStoreClusterNoForce() {
388 integration.SkipIf(s.Framework)
389
390 var response struct{ ResetCluster bool }
391 mutation := resetClusterMutation(resetClusterEdgeID, false)
392 err := ResolverClient.Post(mutation, &response)
393 s.ErrorContains(err, services.ErrMustForceClusterReset.Error())
394 }
395
396 func (s *Suite) TestResetNonStoreClusterForce() {
397 integration.SkipIf(s.Framework)
398
399 clusterInfraID := "3396a52c-6a22-4049-9593-5a63b596a200"
400 var response struct{ ResetCluster bool }
401 mutation := resetClusterMutation(clusterInfraID, true)
402 err := ResolverClient.Post(mutation, &response)
403 s.ErrorContains(err, services.ErrCanOnlyResetStore.Error())
404 }
405
406 func resetClusterMutation(clusterEdgeID string, force bool) string {
407 return MustParse(graphb.Query{
408 Type: graphb.TypeMutation,
409 Fields: []*graphb.Field{
410 {
411 Name: "resetCluster",
412 Arguments: []graphb.Argument{
413 graphb.ArgumentString("clusterEdgeId", clusterEdgeID),
414 graphb.ArgumentBool("force", force),
415 },
416 },
417 },
418 })
419 }
420
View as plain text