1 package integration_test
2
3 import (
4 "context"
5 "database/sql"
6 _ "embed"
7 "fmt"
8 "net/http"
9 "net/http/httptest"
10 "strings"
11 "time"
12
13 "edge-infra.dev/pkg/edge/api/apierror"
14 "edge-infra.dev/pkg/edge/api/graph/mapper"
15 "edge-infra.dev/pkg/edge/api/graph/model"
16 sqlquery "edge-infra.dev/pkg/edge/api/sql"
17 "edge-infra.dev/pkg/edge/api/utils"
18 "edge-infra.dev/test/framework/integration"
19
20 helmApi "github.com/fluxcd/helm-controller/api/v2"
21 "github.com/udacity/graphb"
22
23 "k8s.io/apimachinery/pkg/util/intstr"
24 )
25
26 const (
27 testHelmEdgeID = "be8536ff-d463-4aff-8fa9-fe81fec1ddc1"
28 helmCharts = `
29 apiVersion: v1
30 entries:
31 test-helm-chart1:
32 - apiVersion: v2
33 version: 0.0.1
34 name: test-helm-chart1
35 urls:
36 - "http://%s/chart.tgz"
37 test-helm-chart2:
38 - apiVersion: v2
39 version: 0.0.2
40 name: test-helm-chart2
41 urls:
42 - "http://%s/chart.tgz"
43 `
44 readme = `
45 # Introduction
46
47 This chart is a umbrella chart for emerald services including selling service, pos config etc.
48
49 # Prerequisites
50 Before deploying the chart you need to:
51 `
52 updateConfigValues = `
53 global:
54 deploymentMode: store
55 gcloud:
56 serviceAccount:
57 enabled: true
58 secret: ewog-testing`
59 schemaData = `
60 {
61 "$schema": "http://json-schema.org/schema#",
62 "type": "object",
63 "properties": {
64 "ingress": {
65 "type": "object",
66 "properties": {
67 "namespace": {
68 "type": "string",
69 "default": "selling-services",
70 "pattern": "^[a-z]+[-]*[a-z]*$"
71 },
72 "services": {
73 "type": "array",
74 "items": {
75 "type": "object",
76 "properties": {
77 "service": {
78 "type": "object",
79 "properties": {
80 "name": {
81 "type": "string",
82 "pattern": "^[a-z]+[-]*[a-z]*$"
83 },
84 "path": {
85 "type": "string",
86 "pattern": "^[A-Za-z0-9_.\/-]*$"
87 },
88 "port": {
89 "type": "integer",
90 "pattern": "^[1-9]*$"
91 }
92 }
93 }
94 }
95 }
96 }
97 }
98 },
99 "selling-configuration": {
100 "type": "object",
101 "properties": {
102 "app": {
103 "type": "object",
104 "properties": {
105 "image": {
106 "type": "string",
107 "default": "ncr-emeraldedge-docker-dev.jfrog.io/selling-configuration",
108 "pattern": "^[A-Za-z0-9_.\/-]*$"
109 },
110 "replicaCount": {
111 "type": "integer",
112 "default": 1,
113 "pattern": "^[1-9]*$"
114 },
115 "version": {
116 "type": "string",
117 "default": "1.0.0",
118 "pattern": "^[0-9.]*$"
119 }
120 }
121 },
122 "livenessProbe": {
123 "type": "object",
124 "properties": {
125 "enabled": {
126 "type": "boolean",
127 "default": true
128 },
129 "healthCheckAPI": {
130 "type": "string",
131 "default": "selling-configuration/health",
132 "pattern": "^[A-Za-z0-9_.\/-]*$"
133 }
134 }
135 },
136 "namespace": {
137 "type": "string",
138 "default": "selling-services",
139 "pattern": "^[a-z]+[-]*[a-z]*$"
140 }
141 }
142 },
143 "selling-configuration-pgsql": {
144 "type": "object",
145 "properties": {
146 "app": {
147 "type": "object",
148 "properties": {
149 "image": {
150 "type": "string",
151 "default": "ncr-emeraldedge-docker-dev.jfrog.io/selling-conf-postgresql",
152 "pattern": "^[A-Za-z0-9_.\/-]*$"
153 },
154 "replicaCount": {
155 "type": "integer",
156 "default": 1,
157 "pattern": "^[1-9]*$"
158 },
159 "version": {
160 "type": "string",
161 "default": "1.0.0",
162 "pattern": "^[0-9.]*$"
163 }
164 }
165 },
166 "namespace": {
167 "type": "string",
168 "default": "selling-services",
169 "pattern": "^[a-z]+[-]*[a-z]*$"
170 }
171 }
172 },
173 "selling-engine": {
174 "type": "object",
175 "properties": {
176 "app": {
177 "type": "object",
178 "required": ["image", "replicaCount", "version"],
179 "properties": {
180 "image": {
181 "type": "string",
182 "default": "ncr-emeraldedge-docker-dev.jfrog.io/selling_engine",
183 "pattern": "^[A-Za-z0-9_.\/-]*$"
184 },
185 "replicaCount": {
186 "type": "integer",
187 "default": 1,
188 "pattern": "^[1-9]*$"
189 },
190 "version": {
191 "type": "string",
192 "default": "1.0.1",
193 "pattern": "^[0-9.]*$"
194 }
195 }
196 },
197 "livenessProbe": {
198 "type": "object",
199 "properties": {
200 "enabled": {
201 "type": "boolean",
202 "default": true
203 },
204 "healthCheckAPI": {
205 "type": "string",
206 "default": "selling-execution/health",
207 "pattern": "^[A-Za-z0-9_.\/-]*$"
208 }
209 }
210 },
211 "namespace": {
212 "type": "string",
213 "default": "selling-services",
214 "pattern": "^[a-z]+[-]*[a-z]*$"
215 }
216 }
217 }
218 }
219 }
220 `
221 )
222
223
224 var zippedChart string
225
226 func (s Suite) TestCreateHelmRelease() {
227 integration.SkipIf(s.Framework)
228 srv := s.createHelmRepoTestServer()
229 helmURL := srv.URL
230 name := fmt.Sprintf("create-helmrelease-%s", s.testTime)
231 var response struct{ CreateOrUpdateSecretManagerSecret bool }
232 mutation := createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, testHelmSecret, "edge", "helm-repository", "tenant", []model.KeyValues{
233 {Key: "helm_repo_name", Value: "podinfo"},
234 {Key: "helmUrl", Value: helmURL},
235 })
236 ResolverClient.MustPost(mutation, &response)
237 s.NotNil(response.CreateOrUpdateSecretManagerSecret)
238 s.Equal(response.CreateOrUpdateSecretManagerSecret, true)
239
240 var res struct{ DefaultSchemaConfig *model.HelmConfig }
241 query := defaultSchemaConfigQuery(testHelmSecret, testOrgBannerEdgeID, testHelmChart, testHelmVersion)
242 s.NoError(GraphqlRetry(query, &res, func() bool { return res.DefaultSchemaConfig != nil }))
243 s.NotNil(res.DefaultSchemaConfig)
244 s.NotEmpty(res.DefaultSchemaConfig.ConfigVals)
245
246
247 var resp struct{ CreateHelmRelease bool }
248 namespace := fmt.Sprintf("helmrelease-%d", time.Now().UnixNano())
249 mutation = s.createHelmReleaseMutation("", testClusterEdgeID, name, namespace, testHelmSecret, testHelmRepo, testHelmChart, testHelmVersion, "", "")
250 ResolverClient.MustPost(mutation, &resp)
251 s.True(resp.CreateHelmRelease)
252
253
254 namespace = fmt.Sprintf("helmrelease-%d", time.Now().UnixNano())
255 mutation = s.createHelmReleaseMutation(testOrgBannerEdgeID, "", name, namespace, testHelmSecret, testHelmRepo, testHelmChart, testHelmVersion, "", "")
256 ResolverClient.MustPost(mutation, &resp)
257 s.True(resp.CreateHelmRelease)
258
259
260 namespace = fmt.Sprintf("helmrelease-%d", time.Now().UnixNano())
261 mutation = s.createHelmReleaseMutation("", "", name, namespace, testHelmSecret, testHelmRepo, testHelmChart, testHelmVersion, "", "")
262 s.Error(ResolverClient.Post(mutation, &resp))
263 s.False(resp.CreateHelmRelease)
264 }
265
266 func (s Suite) TestCreateExternalSecretHelmRelease() {
267 integration.SkipIf(s.Framework)
268 srv := s.createHelmRepoTestServer()
269 helmURL := srv.URL
270 namespace := fmt.Sprintf("secret-ns-%d", time.Now().UnixNano())
271 name := fmt.Sprintf("external-secret-helmrelease-%d", time.Now().UnixNano())
272
273 var resp struct{ CreateHelmRelease bool }
274 testSecret1 := "test-secret-1"
275 testSecret2 := "test-secret-2"
276
277 var response struct{ CreateOrUpdateSecretManagerSecret bool }
278 mutation := createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, testSecret1, "edge", "docker-registry", "tenant", []model.KeyValues{
279 {Key: "docker-username", Value: "jd250001"},
280 {Key: "docker-password", Value: "password1"},
281 {Key: "docker-server", Value: "https://example.com"},
282 })
283 ResolverClient.MustPost(mutation, &response)
284 s.NotNil(response.CreateOrUpdateSecretManagerSecret)
285 s.Equal(response.CreateOrUpdateSecretManagerSecret, true)
286
287 mutation = createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, testSecret2, "edge", "helm-repository", "tenant", []model.KeyValues{
288 {Key: "helm_repo_name", Value: "podinfo"},
289 {Key: "helmUrl", Value: helmURL},
290 })
291 ResolverClient.MustPost(mutation, &response)
292 s.NotNil(response.CreateOrUpdateSecretManagerSecret)
293 s.Equal(response.CreateOrUpdateSecretManagerSecret, true)
294
295 mutation = createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, testHelmSecret, "edge", "helm-repository", "tenant", []model.KeyValues{
296 {Key: "helm_repo_name", Value: "podinfo"},
297 {Key: "helmUrl", Value: helmURL},
298 })
299 ResolverClient.MustPost(mutation, &response)
300 s.NotNil(response.CreateOrUpdateSecretManagerSecret)
301 s.Equal(response.CreateOrUpdateSecretManagerSecret, true)
302
303 clusterEdgeID := "3396a52c-6a22-4049-9593-5a63b596a205"
304 mutation = s.createHelmReleaseMutation(testOrgBannerEdgeID, clusterEdgeID, name, namespace, testHelmSecret, testHelmRepo, testHelmChart, testHelmVersion, "", testSecret1, testSecret2)
305 ResolverClient.MustPost(mutation, &resp)
306 s.True(resp.CreateHelmRelease)
307
308 helmEdgeID, err := s.getHelmEdgeIDByNameAndID(s.ctx, name, nil, &testOrgBannerEdgeID)
309 s.NoError(err)
310
311 var res struct{ HelmWorkload *model.HelmWorkload }
312 query := helmWorkloadQuery(clusterEdgeID, helmEdgeID)
313 ResolverClient.MustPost(query, &res)
314 s.NotNil(res.HelmWorkload)
315 s.Equal(testHelmVersion, res.HelmWorkload.HelmChartVersion)
316 s.NotNil(res.HelmWorkload.ConfigValues)
317 s.Equal("", *res.HelmWorkload.ConfigValues)
318 s.NotNil(res.HelmWorkload.InstalledBy)
319 s.Equal("acct:emerald-edge-dev@testing", *res.HelmWorkload.InstalledBy)
320 }
321
322 func (s Suite) TestCreateInvalidHelmRelease() {
323 integration.SkipIf(s.Framework)
324 var resp struct{ CreateHelmRelease bool }
325
326 name := fmt.Sprintf("Create-helmrelease-%s", s.testTime)
327 namespace := fmt.Sprintf("helmrelease-%s", s.testTime)
328 mutation := s.createHelmReleaseMutation(testOrgBannerEdgeID, testClusterEdgeID, name, namespace, testHelmSecret, testHelmRepo, testHelmChart, testHelmVersion, "", "")
329 err := ResolverClient.Post(mutation, &resp)
330 s.Error(err)
331 s.Contains(err.Error(), "invalid name for helm resource")
332 s.False(resp.CreateHelmRelease)
333
334 name = fmt.Sprintf("create-helmrelease-%s", s.testTime)
335 namespace = fmt.Sprintf("Helmrelease-%s", s.testTime)
336 mutation = s.createHelmReleaseMutation(testOrgBannerEdgeID, testClusterEdgeID, name, namespace, testHelmSecret, testHelmRepo, testHelmChart, testHelmVersion, "", "")
337 err = ResolverClient.Post(mutation, &resp)
338 s.Error(err)
339 s.Contains(err.Error(), "invalid namespace for helm resource")
340 s.False(resp.CreateHelmRelease)
341 }
342
343 func (s Suite) TestDeleteHelmRelease() {
344 integration.SkipIf(s.Framework)
345
346
347 helmEdgeID := "29b8709a-2288-4054-829a-6dbfa8cf9eec"
348 var deleteResponse struct{ DeleteHelmRelease bool }
349 mutation := deleteHelmReleaseMutation(helmEdgeID, "", "")
350 ResolverClient.MustPost(mutation, &deleteResponse)
351 s.True(deleteResponse.DeleteHelmRelease)
352 }
353
354 func (s Suite) TestDeleteHelmRelease_Invalid() {
355 integration.SkipIf(s.Framework)
356 name := "duplicate-workload-name"
357
358
359 var deleteResponse struct{ DeleteHelmRelease bool }
360 mutation := deleteHelmReleaseMutation("", "", "")
361 err := ResolverClient.Post(mutation, &deleteResponse)
362 s.Error(err)
363 s.False(deleteResponse.DeleteHelmRelease)
364
365
366 mutation = deleteHelmReleaseMutation("", "", name)
367 err = ResolverClient.Post(mutation, &deleteResponse)
368 s.Error(err)
369 s.False(deleteResponse.DeleteHelmRelease)
370
371
372
373 mutation = deleteHelmReleaseMutation("", clusterEdgeID, name)
374 err = ResolverClient.Post(mutation, &deleteResponse)
375 s.Error(err)
376 s.False(deleteResponse.DeleteHelmRelease)
377
378
379
380
381 helmEdgeID := "aa015539-3de1-4ec9-bc98-4c9dcc8841e0"
382 mutation = deleteHelmReleaseMutation(helmEdgeID, "", "")
383 err = ResolverClient.Post(mutation, &deleteResponse)
384 s.Error(err)
385 s.False(deleteResponse.DeleteHelmRelease)
386 }
387
388 func (s Suite) TestCreateOrUpdateBannerHelmRepository() {
389 integration.SkipIf(s.Framework)
390 name := fmt.Sprintf("create-helmrepo-%s", s.testTime)
391
392 var response struct{ CreateOrUpdateBannerHelmRepository bool }
393 mutation := createOrUpdateBannerHelmRepositoryMutation(testOrgBannerEdgeID, name, testHelmRepoURL, testHelmSecret)
394 ResolverClient.MustPost(mutation, &response)
395 s.True(response.CreateOrUpdateBannerHelmRepository, "unable to create HelmRepository")
396
397 mutation = createOrUpdateBannerHelmRepositoryMutation(testOrgBannerEdgeID, name, testHelmRepoURL, testHelmSecret)
398 ResolverClient.MustPost(mutation, &response)
399 s.True(response.CreateOrUpdateBannerHelmRepository, "unable to update HelmRepository")
400 }
401
402 func (s Suite) TestCreateOrUpdateInvalidBannerHelmRepository() {
403 integration.SkipIf(s.Framework)
404 name := fmt.Sprintf("Create-helmrepo-%s", s.testTime)
405
406 var response struct{ CreateOrUpdateBannerHelmRepository bool }
407 mutation := createOrUpdateBannerHelmRepositoryMutation(testOrgBannerEdgeID, name, testHelmRepoURL, testHelmSecret)
408 err := ResolverClient.Post(mutation, &response)
409 s.Error(err)
410 s.Contains(err.Error(), "invalid name for helm repository")
411 s.False(response.CreateOrUpdateBannerHelmRepository)
412 }
413
414 func (s Suite) TestDeleteBannerHelmRepository() {
415 integration.SkipIf(s.Framework)
416 name := fmt.Sprintf("delete-helmrepo-%s", s.testTime)
417
418 var response struct{ CreateOrUpdateBannerHelmRepository bool }
419 mutation := createOrUpdateBannerHelmRepositoryMutation(testOrgBannerEdgeID, name, testHelmRepoURL, testHelmSecret)
420 ResolverClient.MustPost(mutation, &response)
421 s.True(response.CreateOrUpdateBannerHelmRepository, "unable to create or update HelmRepository")
422 }
423
424 func (s Suite) TestUpdateHelmRelease_Invalid() {
425 integration.SkipIf(s.Framework)
426 name := "duplicate-workload-name"
427
428
429 var updatedResponse struct{ UpdateHelmRelease bool }
430 mutation := updateHelmReleaseMutation("", "", "", testHelmUpdatedVersion, "", nil, nil)
431 err := ResolverClient.Post(mutation, &updatedResponse)
432 s.Error(err)
433 s.False(updatedResponse.UpdateHelmRelease)
434
435
436 mutation = updateHelmReleaseMutation("", "", name, testHelmUpdatedVersion, "", nil, nil)
437 err = ResolverClient.Post(mutation, &updatedResponse)
438 s.Error(err)
439 s.False(updatedResponse.UpdateHelmRelease)
440
441
442
443 mutation = updateHelmReleaseMutation("", testClusterEdgeID, name, testHelmUpdatedVersion, "", nil, nil)
444 err = ResolverClient.Post(mutation, &updatedResponse)
445 s.Error(err)
446 s.False(updatedResponse.UpdateHelmRelease)
447 }
448
449 func (s Suite) TestUpdateHelmRelease() {
450 integration.SkipIf(s.Framework)
451 helmURL := testHelmRepoURL
452 if !integration.IsIntegrationTest() {
453 srv := s.createHelmRepoTestServer()
454 helmURL = srv.URL
455 }
456
457 namespace := fmt.Sprintf("helmrelease-%s", s.testTime)
458 chartSecret := fmt.Sprintf("chart-secret-%s", s.testTime)
459 name := "test-helm-release"
460 secrets := []string{"test-secret-1", "test-secret-2"}
461
462 testLabelEdgeIDs := []string{"442f2e77-279d-45af-acae-4ec5458b7e00"}
463
464 var secretResponse struct{ CreateOrUpdateSecretManagerSecret bool }
465 mutation := createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, chartSecret, "edge-helm", "helm-repository", "tenant", []model.KeyValues{
466 {Key: "helm_repo_name", Value: testHelmRepo},
467 {Key: "helmUrl", Value: helmURL},
468 })
469 ResolverClient.MustPost(mutation, &secretResponse)
470 s.True(secretResponse.CreateOrUpdateSecretManagerSecret)
471
472 var secretManagerQuery struct{ SecretManagerSecret model.SecretManagerResponse }
473 secretQuery := getSecretManagerSecret(chartSecret, testOrgBannerEdgeID, true)
474 ResolverClient.MustPost(secretQuery, &secretManagerQuery)
475 s.Equal(len(secretManagerQuery.SecretManagerSecret.Values), 2)
476
477 var response struct{ DefaultSchemaConfig *model.HelmConfig }
478 query := defaultSchemaConfigQuery(chartSecret, testOrgBannerEdgeID, testHelmChart, testHelmVersion)
479 s.NoError(GraphqlRetry(query, &response, func() bool { return response.DefaultSchemaConfig != nil }))
480 s.NotNil(response.DefaultSchemaConfig)
481 s.NotEmpty(response.DefaultSchemaConfig.ConfigVals)
482
483 ucv := strings.ReplaceAll(updateConfigValues, "\n", "\\n")
484 var resp struct{ CreateHelmRelease bool }
485 mutation = s.createHelmReleaseMutation(testOrgBannerEdgeID, testClusterEdgeID, name, namespace, testHelmSecret, testHelmRepo, testHelmChart, testHelmVersion, "", "")
486 ResolverClient.MustPost(mutation, &resp)
487 s.True(resp.CreateHelmRelease)
488
489 helmEdgeID, err := s.getHelmEdgeIDByNameAndID(s.ctx, name, nil, &testOrgBannerEdgeID)
490 s.NoError(err)
491
492
493 var updatedResponse struct{ UpdateHelmRelease bool }
494 mutation = updateHelmReleaseMutation(helmEdgeID, "", "", testHelmVersion, ucv, secrets, testLabelEdgeIDs)
495 ResolverClient.MustPost(mutation, &updatedResponse)
496 s.True(updatedResponse.UpdateHelmRelease)
497
498 var res struct{ HelmWorkload *model.HelmWorkload }
499 query = helmWorkloadQuery(testClusterEdgeID, helmEdgeID)
500 ResolverClient.MustPost(query, &res)
501 s.NotNil(res.HelmWorkload)
502 s.Equal(testHelmVersion, res.HelmWorkload.HelmChartVersion)
503 s.NotNil(res.HelmWorkload.ConfigValues)
504 s.NotEqual("", *res.HelmWorkload.ConfigValues)
505 s.NotNil(res.HelmWorkload.InstalledBy)
506 s.Equal("acct:emerald-edge-dev@testing", *res.HelmWorkload.InstalledBy)
507 s.NotEmpty(res.HelmWorkload.Secrets)
508 s.NotEmpty(res.HelmWorkload.Labels)
509
510
511 mutation = updateHelmReleaseMutation("", testClusterEdgeID, name, "", ucv, []string{}, []string{})
512 ResolverClient.MustPost(mutation, &updatedResponse)
513 s.True(updatedResponse.UpdateHelmRelease)
514
515 query = helmWorkloadQuery(testClusterEdgeID, helmEdgeID)
516 ResolverClient.MustPost(query, &res)
517 s.NotNil(res.HelmWorkload)
518 s.Equal(testHelmVersion, res.HelmWorkload.HelmChartVersion)
519 s.NotNil(res.HelmWorkload.ConfigValues)
520 s.NotEqual("", *res.HelmWorkload.ConfigValues)
521 s.NotNil(res.HelmWorkload.InstalledBy)
522 s.Equal("acct:emerald-edge-dev@testing", *res.HelmWorkload.InstalledBy)
523 s.Empty(res.HelmWorkload.Secrets)
524 s.Empty(res.HelmWorkload.Labels)
525 }
526
527 func (s Suite) TestHelmChartVersion() {
528 integration.SkipIf(s.Framework)
529 helmURL := testHelmRepoURL
530 if !integration.IsIntegrationTest() {
531 srv := s.createHelmRepoTestServer()
532 helmURL = srv.URL
533 }
534
535 chartSecret := fmt.Sprintf("version-chart-secret-%s", s.testTime)
536 var secretResponse struct{ CreateOrUpdateSecretManagerSecret bool }
537 mutation := createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, chartSecret, "edge-helm", "helm-repository", "tenant", []model.KeyValues{
538 {Key: "username", Value: "jd250001"},
539 {Key: "password", Value: "password1"},
540 {Key: "helmUrl", Value: helmURL},
541 })
542 ResolverClient.MustPost(mutation, &secretResponse)
543 s.True(secretResponse.CreateOrUpdateSecretManagerSecret)
544
545 var resp struct{ HelmChartVersion *model.HelmChartResponse }
546 query := helmChartVersionQuery(testHelmChart, chartSecret, testOrgBannerEdgeID)
547 s.NoError(GraphqlRetry(query, &resp, func() bool { return resp.HelmChartVersion != nil }))
548 s.NotNil(resp.HelmChartVersion)
549 s.NotEmpty(resp.HelmChartVersion.Name)
550 s.NotEmpty(resp.HelmChartVersion.Versions)
551 }
552
553 func (s Suite) TestDefaultSchemaConfig() {
554 integration.SkipIf(s.Framework)
555 helmURL := testHelmRepoURL
556 if !integration.IsIntegrationTest() {
557 srv := s.createHelmRepoTestServer()
558 helmURL = srv.URL
559 }
560
561 chartSecret := fmt.Sprintf("config-chart-secret-%s", s.testTime)
562 var secretResponse struct{ CreateOrUpdateSecretManagerSecret bool }
563 mutation := createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, chartSecret, "edge-helm", "helm-repository", "tenant", []model.KeyValues{
564 {Key: "username", Value: "jd250001"},
565 {Key: "password", Value: "password1"},
566 {Key: "helmUrl", Value: helmURL},
567 })
568 ResolverClient.MustPost(mutation, &secretResponse)
569 s.True(secretResponse.CreateOrUpdateSecretManagerSecret)
570
571 var resp struct{ DefaultSchemaConfig *model.HelmConfig }
572 query := defaultSchemaConfigQuery(chartSecret, testOrgBannerEdgeID, testHelmChart, testHelmVersion)
573 s.NoError(GraphqlRetry(query, &resp, func() bool { return resp.DefaultSchemaConfig != nil }))
574 s.NotNil(resp.DefaultSchemaConfig)
575 s.NotEmpty(resp.DefaultSchemaConfig.ConfigVals)
576 }
577
578 func (s Suite) TestHelmRelease() {
579 integration.SkipIf(s.Framework)
580 if !integration.IsIntegrationTest() {
581 srv := s.createHelmRepoTestServer()
582 s.NoError(createTestHelmRepoSecret(testOrgBannerEdgeID, testHelmSecret, srv.URL))
583 }
584
585 namespace := fmt.Sprintf("helmrelease-%s", s.testTime)
586 name := fmt.Sprintf("helmreleases-%s", s.testTime)
587
588 var resp struct{ CreateHelmRelease bool }
589 mutation := s.createHelmReleaseMutation(testOrgBannerEdgeID, testClusterEdgeID, name, namespace, testHelmSecret, testHelmRepo, testHelmChart, testHelmVersion, "", "")
590 ResolverClient.MustPost(mutation, &resp)
591
592 s.True(resp.CreateHelmRelease)
593 }
594
595 func (s Suite) TestHelmReleasesStatus() {
596 integration.SkipIf(s.Framework)
597 helmURL := testHelmRepoURL
598 if !integration.IsIntegrationTest() {
599 srv := s.createHelmRepoTestServer()
600 helmURL = srv.URL
601 }
602
603 chartSecret := fmt.Sprintf("chart-secret-%s", s.testTime)
604
605 var secretResponse struct{ CreateOrUpdateSecretManagerSecret bool }
606 mutation := createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, chartSecret, "edge-helm", "helm-repository", "tenant", []model.KeyValues{
607 {Key: "helm_repo_name", Value: testHelmRepo},
608 {Key: "helmUrl", Value: helmURL},
609 })
610 ResolverClient.MustPost(mutation, &secretResponse)
611 s.True(secretResponse.CreateOrUpdateSecretManagerSecret)
612
613 var secretManagerQuery struct{ SecretManagerSecret model.SecretManagerResponse }
614 secretQuery := getSecretManagerSecret(chartSecret, testOrgBannerEdgeID, true)
615 ResolverClient.MustPost(secretQuery, &secretManagerQuery)
616 s.Equal(len(secretManagerQuery.SecretManagerSecret.Values), 2)
617
618 var response struct{ HelmReleasesStatus []*model.HelmReleaseStatus }
619 query := helmReleasesStatusQuery(testClusterEdgeID)
620 s.NoError(GraphqlRetry(query, &response, func() bool { return len(response.HelmReleasesStatus) > 0 }))
621 for _, helmReleasesStatus := range response.HelmReleasesStatus {
622 s.NotEmpty(helmReleasesStatus.Name)
623 s.Empty(helmReleasesStatus.LastActionTime)
624 s.Empty(helmReleasesStatus.VersionInstalled)
625 s.NotEmpty(helmReleasesStatus.VersionRequested)
626 s.Empty(helmReleasesStatus.InstallCondition)
627 s.Empty(helmReleasesStatus.ReadyCondition)
628 s.Empty(helmReleasesStatus.ConfigValues)
629 }
630 }
631
632 func (s Suite) TestHelmCharts() {
633 integration.SkipIf(s.Framework)
634 helmURL := testHelmRepoURL
635 if !integration.IsIntegrationTest() {
636 srv := s.createHelmRepoTestServer()
637 helmURL = srv.URL
638 }
639
640 chartSecret := fmt.Sprintf("helm-chart-secret-%s", s.testTime)
641 var secretResponse struct{ CreateOrUpdateSecretManagerSecret bool }
642 mutation := createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, chartSecret, "edge-helm", "helm-repository", "tenant", []model.KeyValues{
643 {Key: "username", Value: "jd250001"},
644 {Key: "password", Value: "password1"},
645 {Key: "helmUrl", Value: helmURL},
646 })
647 ResolverClient.MustPost(mutation, &secretResponse)
648 s.True(secretResponse.CreateOrUpdateSecretManagerSecret)
649
650 var resp struct{ HelmCharts []*model.HelmChart }
651 query := helmChartsQuery(chartSecret, testOrgBannerEdgeID)
652 s.NoError(GraphqlRetry(query, &resp, func() bool { return len(resp.HelmCharts) > 0 }))
653 s.Len(resp.HelmCharts, 2)
654 s.NotEmpty(resp.HelmCharts[0].Name)
655 s.NotEmpty(resp.HelmCharts[1].Name)
656 }
657
658 func (s Suite) TestHelmRepositoryInfo() {
659 integration.SkipIf(s.Framework)
660 helmURL := testHelmRepoURL
661 if !integration.IsIntegrationTest() {
662 srv := s.createHelmRepoTestServer()
663 helmURL = srv.URL
664 }
665
666 chartSecret := fmt.Sprintf("helmrepo-info-secret-%s", s.testTime)
667 var secretResponse struct{ CreateOrUpdateSecretManagerSecret bool }
668 mutation := createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, chartSecret, "edge-helm", "helm-repository", "tenant", []model.KeyValues{
669 {Key: "username", Value: "jd250001"},
670 {Key: "password", Value: "password1"},
671 {Key: "helmUrl", Value: helmURL},
672 })
673 ResolverClient.MustPost(mutation, &secretResponse)
674 s.True(secretResponse.CreateOrUpdateSecretManagerSecret)
675
676 var resp struct{ HelmRepositoryInfo *model.HelmRepositoryInfo }
677 query := helmRepositoryInfoQuery(chartSecret, testOrgBannerEdgeID, testHelmChart, testHelmVersion)
678 s.NoError(GraphqlRetry(query, &resp, func() bool { return resp.HelmRepositoryInfo != nil }))
679 s.NotNil(resp.HelmRepositoryInfo)
680 s.NotEmpty(resp.HelmRepositoryInfo.Readme)
681 }
682
683 func (s Suite) TestGetHelmWorkloads() {
684 integration.SkipIf(s.Framework)
685
686 srv := s.createHelmRepoTestServer()
687 helmURL := srv.URL
688
689 var secretResponse struct{ CreateOrUpdateSecretManagerSecret bool }
690 mutation := createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, "test-helm-workload", "edge-helm", "helm-repository", "tenant", []model.KeyValues{
691 {Key: "username", Value: "jd250001"},
692 {Key: "password", Value: "password1"},
693 {Key: "helmUrl", Value: helmURL},
694 })
695
696 ResolverClient.MustPost(mutation, &secretResponse)
697 s.True(secretResponse.CreateOrUpdateSecretManagerSecret)
698
699 var response struct{ HelmWorkloads []*model.HelmWorkload }
700 query := helmWorkloadsQuery(testClusterEdgeID, "")
701
702 s.NoError(GraphqlRetry(query, &response, func() bool { return len(response.HelmWorkloads) > 0 }))
703
704 responseMap := make(map[string]bool, 0)
705 for i := 0; i < len(response.HelmWorkloads); i++ {
706 if responseMap[response.HelmWorkloads[i].HelmEdgeID] {
707 s.Fail(fmt.Sprintf("duplicate helm release returned: %s", response.HelmWorkloads[i].Name))
708 } else {
709 responseMap[response.HelmWorkloads[i].HelmEdgeID] = true
710 }
711 }
712
713 s.NotNil(response.HelmWorkloads)
714 s.GreaterOrEqual(len(response.HelmWorkloads), 1)
715 s.Equal(testClusterEdgeID, response.HelmWorkloads[0].ClusterEdgeID)
716 s.NotEmpty(response.HelmWorkloads[0].Name)
717 for _, helmWorkloadVal := range response.HelmWorkloads {
718 s.NotEmpty(helmWorkloadVal.HelmEdgeID)
719 s.NotEmpty(helmWorkloadVal.HelmChart)
720 s.NotEmpty(helmWorkloadVal.HelmChartVersion)
721 s.NotEmpty(helmWorkloadVal.HelmRepoSecret)
722 s.NotEmpty(helmWorkloadVal.HelmRepository)
723 s.NotEmpty(helmWorkloadVal.Namespace)
724 s.NotEmpty(helmWorkloadVal.InstalledBy)
725 s.Empty(*helmWorkloadVal.UpdateAvailable)
726 s.NotEmpty(helmWorkloadVal.UpdatedAt)
727 s.NotEmpty(helmWorkloadVal.CreatedAt)
728 s.Equal(helmWorkloadVal.Labels, []*model.Label(nil))
729 }
730
731
732
733 undeployedHelmEdgeID := "930c89f4-060b-456e-a779-7cacb50c3bec"
734 deployedHelmEdgeID := testHelmEdgeID
735 query = helmWorkloadsQuery("", testOrgBannerEdgeID)
736 s.NoError(ResolverClient.Post(query, &response))
737 s.NotEmpty(response.HelmWorkloads)
738
739 for _, workload := range response.HelmWorkloads {
740 if workload.HelmEdgeID == undeployedHelmEdgeID {
741 s.Empty(workload.ClusterEdgeID)
742 } else if workload.HelmEdgeID == deployedHelmEdgeID {
743 s.Equal(testClusterEdgeID, workload.ClusterEdgeID)
744 }
745 s.Equal(testOrgBannerEdgeID, workload.BannerEdgeID)
746 s.NotEmpty(workload.Name)
747 s.NotEmpty(workload.HelmEdgeID)
748 s.NotEmpty(workload.HelmChart)
749 s.NotEmpty(workload.HelmChartVersion)
750 s.NotEmpty(workload.HelmRepoSecret)
751 s.NotEmpty(workload.HelmRepository)
752 s.NotEmpty(workload.Namespace)
753 s.NotEmpty(workload.InstalledBy)
754 s.Empty(*workload.UpdateAvailable)
755 s.NotEmpty(workload.UpdatedAt)
756 s.NotEmpty(workload.CreatedAt)
757 s.Equal(workload.Labels, []*model.Label(nil))
758 }
759 }
760
761 func (s Suite) TestGetHelmWorkload() {
762 integration.SkipIf(s.Framework)
763
764 srv := s.createHelmRepoTestServer()
765 helmURL := srv.URL
766
767 var secretResponse struct{ CreateOrUpdateSecretManagerSecret bool }
768 mutation := createOrUpdateSecretManagerSecretMutation(testOrgBannerEdgeID, "test-helm-workload", "edge-helm", "helm-repository", "tenant", []model.KeyValues{
769 {Key: "username", Value: "jd250001"},
770 {Key: "password", Value: "password1"},
771 {Key: "helmUrl", Value: helmURL},
772 })
773
774 s.NoError(ResolverClient.Post(mutation, &secretResponse))
775 s.True(secretResponse.CreateOrUpdateSecretManagerSecret)
776
777 var response struct{ HelmWorkload *model.HelmWorkload }
778 query := helmWorkloadQuery(testClusterEdgeID, testHelmEdgeID)
779 s.NoError(ResolverClient.Post(query, &response))
780
781 s.NotNil(response.HelmWorkload)
782 s.NotEmpty(response.HelmWorkload.Name)
783 s.Equal(response.HelmWorkload.Name, "test-helm-workload")
784 s.NotEmpty(response.HelmWorkload.HelmEdgeID)
785 s.NotEmpty(response.HelmWorkload.HelmChart)
786 s.Equal(testOrgBannerEdgeID, response.HelmWorkload.BannerEdgeID)
787 s.Equal(testClusterEdgeID, response.HelmWorkload.ClusterEdgeID)
788 s.NotEmpty(response.HelmWorkload.HelmChartVersion)
789 s.NotEmpty(response.HelmWorkload.HelmRepoSecret)
790 s.NotEmpty(response.HelmWorkload.HelmRepository)
791 s.NotEmpty(response.HelmWorkload.Namespace)
792 s.NotEmpty(response.HelmWorkload.InstalledBy)
793 s.Empty(*response.HelmWorkload.UpdateAvailable)
794 s.NotEmpty(response.HelmWorkload.UpdatedAt)
795 s.NotEmpty(response.HelmWorkload.CreatedAt)
796 s.Equal(response.HelmWorkload.UpgradeableVersions, []*model.HelmVersion(nil))
797 s.Equal(response.HelmWorkload.DowngradeableVersions, []*model.HelmVersion(nil))
798 s.Equal(len(response.HelmWorkload.Secrets), 2)
799 s.NotEmpty(response.HelmWorkload.Labels)
800 }
801
802 func (s Suite) TestAddWorkloadLabels() {
803 integration.SkipIf(s.Framework)
804
805 labelIDList := []string{"ca18bfab-091b-4a7f-9db6-011d2603b949", "bbb5a40b-65d1-4092-ab5f-e35d7c2482db"}
806 invalidabelIDList := []string{"ca18bfabCHIPPY2603b949", "442SCOOBYDOO458b7536"}
807
808
809 var response1 struct {
810 AddWorkloadLabels bool
811 }
812 mutation1 := addWorkloadLabelsMutation(testHelmEdgeID, labelIDList)
813 ResolverClient.MustPost(mutation1, &response1)
814 s.NotNil(response1)
815 s.Equal(true, response1.AddWorkloadLabels)
816
817
818 var response2 struct {
819 AddWorkloadLabels bool
820 }
821 mutation2 := addWorkloadLabelsMutation(testHelmEdgeID, invalidabelIDList)
822 err2 := ResolverClient.Post(mutation2, &response2)
823 s.Equal(false, response2.AddWorkloadLabels)
824 s.Contains(err2.Error(), "[{\"message\":\"Invalid input syntax for type\",\"extensions\":{\"additional\":{\"errorType\":\"EDGE_SQL_STATE\",\"severity\":\"\",\"statusCode\":\"Unknown\"}")
825 }
826
827 func (s Suite) TestDeleteWorkloadLabels() {
828 integration.SkipIf(s.Framework)
829
830 helmEdgeID := "be8536ff-d463-4aff-8fa9-fe81fec1ddc2"
831 labelEdgeID := "aac1f183-50bc-453f-a822-9ab11aa70916"
832 invalidLabel := "jibberish"
833 deleteLabel := "bbb5a40b-65d1-4092-ab5f-e35d7c2482dc"
834
835 workloadLabelInput := model.WorkloadLabelInput{
836 HelmEdgeID: helmEdgeID,
837 LabelEdgeID: labelEdgeID,
838 }
839
840
841 var response1 struct {
842 DeleteWorkloadLabel bool
843 }
844 mutation1 := deleteWorkloadLabelMutation(workloadLabelInput.HelmEdgeID, workloadLabelInput.LabelEdgeID)
845 ResolverClient.MustPost(mutation1, &response1)
846 s.NotNil(response1)
847
848
849 var response2 struct {
850 DeleteWorkloadLabel bool
851 }
852 mutation2 := deleteWorkloadLabelMutation(workloadLabelInput.HelmEdgeID, invalidLabel)
853 err2 := ResolverClient.Post(mutation2, &response2)
854 s.Equal(false, response2.DeleteWorkloadLabel)
855 s.Contains(err2.Error(), "[{\"message\":\"failed to delete labels from workload\",\"path\":[\"deleteWorkloadLabel\"]}]")
856
857
858 var response3 struct {
859 DeleteWorkloadLabel bool
860 }
861 mutation3 := deleteWorkloadLabelMutation(workloadLabelInput.HelmEdgeID, "")
862 ResolverClient.MustPost(mutation3, &response3)
863 s.NotNil(response3)
864 s.Equal(true, response3.DeleteWorkloadLabel)
865
866
867 var response4 struct {
868 DeleteWorkloadLabel bool
869 }
870 mutation4 := deleteWorkloadLabelMutation("", deleteLabel)
871 ResolverClient.MustPost(mutation4, &response4)
872 s.NotNil(response4)
873 s.Equal(true, response4.DeleteWorkloadLabel)
874 }
875
876 func (s Suite) createHelmRepoTestServer() *httptest.Server {
877 return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
878 var err error
879 w.WriteHeader(200)
880 if strings.HasSuffix(r.URL.String(), "/README.md") {
881 _, err = w.Write([]byte(readme))
882 } else if strings.HasSuffix(r.URL.String(), "/values.schema.json") {
883 _, err = w.Write([]byte(schemaData))
884 } else if strings.HasSuffix(r.URL.String(), ".tgz") {
885 _, err = w.Write([]byte(zippedChart))
886 w.Header().Set("Content-Type", "application/gzip")
887 w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.tgz\"", "alpine-0.2.0.tgz"))
888 } else {
889 _, err = w.Write([]byte(getTestHelmRepoIndex(helmCharts, r.Host)))
890 }
891 s.NoError(err)
892 }))
893 }
894
895 func getTestHelmRepoIndex(helmCharts, url string) string {
896 return fmt.Sprintf(helmCharts, url, url)
897 }
898
899 func createTestHelmRepoSecret(bannerEdgeID, name, helmURL string) error {
900 var createResponse struct{ CreateOrUpdateSecretManagerSecret bool }
901 mutation := createOrUpdateSecretManagerSecretMutation(bannerEdgeID, name, "edge-helm", "helm-repository", "tenant", []model.KeyValues{
902 {Key: "helm_repo_name", Value: name},
903 {Key: "helmUrl", Value: helmURL},
904 })
905 ResolverClient.MustPost(mutation, &createResponse)
906 mutation = createOrUpdateBannerHelmRepositoryMutation(bannerEdgeID, name, testHelmRepoURL, name)
907 var createUpdateRepositoryResponse struct{ CreateOrUpdateBannerHelmRepository bool }
908 ResolverClient.MustPost(mutation, &createUpdateRepositoryResponse)
909 if !createUpdateRepositoryResponse.CreateOrUpdateBannerHelmRepository {
910 return fmt.Errorf("unable to create or update HelmRepository")
911 }
912
913 return nil
914 }
915
916 func (s *Suite) createHelmReleaseMutation(bannerEdgeID, clusterEdgeID, name, namespace, secret, helmRepository, helmChart, version, configValues string, helmEdgeID string, secrets ...string) string {
917 payloadArgs := []graphb.Argument{
918 graphb.ArgumentString("name", name),
919 graphb.ArgumentString("secret", secret),
920 graphb.ArgumentString("helmRepository", helmRepository),
921 graphb.ArgumentString("helmChart", helmChart),
922 graphb.ArgumentString("version", version),
923 graphb.ArgumentString("configValues", ""),
924 }
925
926 if bannerEdgeID != "" {
927 payloadArgs = append(payloadArgs, graphb.ArgumentString("bannerEdgeId", bannerEdgeID))
928 }
929 if clusterEdgeID != "" {
930 payloadArgs = append(payloadArgs, graphb.ArgumentString("clusterEdgeId", clusterEdgeID))
931 }
932 if len(secrets) > 0 {
933 payloadArgs = append(payloadArgs, graphb.ArgumentStringSlice("secrets", secrets...))
934 }
935 if namespace != "" {
936 payloadArgs = append(payloadArgs, graphb.ArgumentString("namespace", namespace))
937 }
938 if configValues != "" {
939 payloadArgs = append(payloadArgs, graphb.ArgumentString("configValues", configValues))
940 }
941 if !integration.IsIntegrationTest() {
942 var installationType model.WorkloadInstallationType
943 obj, err := mapper.ToCreateHelmRelease(name, helmRepository, helmChart, version, secret, namespace, nil, installationType, nil, "0.21", helmEdgeID)
944 s.NoError(err)
945 s.NoError(createHelmReleaseResources(obj.(*helmApi.HelmRelease)))
946 }
947 return MustParse(graphb.Query{
948 Type: graphb.TypeMutation,
949 Fields: []*graphb.Field{
950 {
951 Name: "createHelmRelease",
952 Arguments: []graphb.Argument{graphb.ArgumentCustomType("payload", payloadArgs...)},
953 },
954 },
955 })
956 }
957
958 func createOrUpdateBannerHelmRepositoryMutation(bannerEdgeID, name, url, secret string) string {
959 args := []graphb.Argument{
960 graphb.ArgumentString("bannerEdgeId", bannerEdgeID),
961 graphb.ArgumentString("name", name),
962 graphb.ArgumentString("url", url),
963 }
964 if secret != "" {
965 args = append(args, graphb.ArgumentString("secret", secret))
966 }
967 return MustParse(graphb.Query{
968 Type: graphb.TypeMutation,
969 Fields: []*graphb.Field{
970 {
971 Name: "createOrUpdateBannerHelmRepository",
972 Arguments: args,
973 },
974 },
975 })
976 }
977
978 func helmChartsQuery(secretName, bannerEdgeID string) string {
979 return MustParse(graphb.Query{
980 Type: graphb.TypeQuery,
981 Fields: []*graphb.Field{
982 {
983 Name: "helmCharts",
984 Arguments: []graphb.Argument{
985 graphb.ArgumentString("secretName", secretName),
986 graphb.ArgumentString("bannerEdgeId", bannerEdgeID),
987 },
988 Fields: graphb.Fields("name", "description", "version", "appVersion", "icon", "keywords", "sources", "urls", "created"),
989 },
990 },
991 })
992 }
993
994 func defaultSchemaConfigQuery(secretName, bannerEdgeID, chartName, chartVersion string) string {
995 paramsArgs := []graphb.Argument{
996 graphb.ArgumentString("bannerEdgeId", bannerEdgeID),
997 graphb.ArgumentString("secretName", secretName),
998 graphb.ArgumentString("chartName", chartName),
999 graphb.ArgumentString("chartVersion", chartVersion),
1000 }
1001 return MustParse(graphb.Query{
1002 Type: graphb.TypeQuery,
1003 Fields: []*graphb.Field{
1004 {
1005 Name: "defaultSchemaConfig",
1006 Arguments: []graphb.Argument{graphb.ArgumentCustomType("params", paramsArgs...)},
1007 Fields: graphb.Fields("configVals", "configSchema"),
1008 },
1009 },
1010 })
1011 }
1012
1013 func helmWorkloadsQuery(clusterEdgeID, bannerEdgeID string) string {
1014 return MustParse(graphb.Query{
1015 Type: graphb.TypeQuery,
1016 Fields: []*graphb.Field{
1017 {
1018 Name: "helmWorkloads",
1019 Arguments: []graphb.Argument{
1020 graphb.ArgumentString("clusterEdgeId", clusterEdgeID),
1021 graphb.ArgumentString("bannerEdgeId", bannerEdgeID),
1022 },
1023 Fields: []*graphb.Field{
1024 graphb.NewField("helmChart"),
1025 graphb.NewField("helmChartVersion"),
1026 graphb.NewField("helmEdgeID"),
1027 graphb.NewField("clusterEdgeID"),
1028 graphb.NewField("bannerEdgeID"),
1029 graphb.NewField("helmRepoSecret"),
1030 graphb.NewField("helmRepository"),
1031 graphb.NewField("installedBy"),
1032 graphb.NewField("name"),
1033 graphb.NewField("namespace"),
1034 graphb.NewField("installationType"),
1035 graphb.NewField("updateAvailable"),
1036 graphb.NewField("configValues"),
1037 graphb.NewField("createdAt"),
1038 graphb.NewField("updatedAt"),
1039 {
1040 Name: "secrets",
1041 Fields: graphb.Fields("createdAt", "name", "secretEdgeID", "updatedAt"),
1042 },
1043 {
1044 Name: "upgradeableVersions",
1045 Fields: graphb.Fields("version"),
1046 },
1047 {
1048 Name: "downgradeableVersions",
1049 Fields: graphb.Fields("version"),
1050 },
1051 },
1052 },
1053 },
1054 })
1055 }
1056
1057 func helmWorkloadQuery(clusterEdgeID string, helmEdgeID string) string {
1058 return MustParse(graphb.Query{
1059 Type: graphb.TypeQuery,
1060 Fields: []*graphb.Field{
1061 {
1062 Name: "helmWorkload",
1063 Arguments: []graphb.Argument{
1064 graphb.ArgumentString("clusterEdgeId", clusterEdgeID),
1065 graphb.ArgumentString("helmEdgeId", helmEdgeID),
1066 },
1067 Fields: []*graphb.Field{
1068 graphb.NewField("bannerEdgeID"),
1069 graphb.NewField("clusterEdgeID"),
1070 graphb.NewField("helmChart"),
1071 graphb.NewField("helmChartVersion"),
1072 graphb.NewField("helmEdgeID"),
1073 graphb.NewField("helmRepoSecret"),
1074 graphb.NewField("helmRepository"),
1075 graphb.NewField("installedBy"),
1076 graphb.NewField("name"),
1077 graphb.NewField("namespace"),
1078 graphb.NewField("installationType"),
1079 graphb.NewField("updateAvailable"),
1080 graphb.NewField("configValues"),
1081 graphb.NewField("createdAt"),
1082 graphb.NewField("updatedAt"),
1083 {
1084 Name: "secrets",
1085 Fields: graphb.Fields("createdAt", "name", "secretEdgeID", "updatedAt"),
1086 },
1087 {
1088 Name: "upgradeableVersions",
1089 Fields: graphb.Fields("version"),
1090 },
1091 {
1092 Name: "downgradeableVersions",
1093 Fields: graphb.Fields("version"),
1094 },
1095 {
1096 Name: "labels",
1097 Fields: graphb.Fields("labelEdgeId", "key", "color", "visible", "editable", "unique", "bannerEdgeId", "description", "type"),
1098 },
1099 },
1100 },
1101 },
1102 })
1103 }
1104
1105 func helmRepositoryInfoQuery(secretName, bannerEdgeID, chartName, chartVersion string) string {
1106 paramsArgs := []graphb.Argument{
1107 graphb.ArgumentString("bannerEdgeId", bannerEdgeID),
1108 graphb.ArgumentString("secretName", secretName),
1109 graphb.ArgumentString("chartName", chartName),
1110 graphb.ArgumentString("chartVersion", chartVersion),
1111 }
1112 return MustParse(graphb.Query{
1113 Type: graphb.TypeQuery,
1114 Fields: []*graphb.Field{
1115 {
1116 Name: "helmRepositoryInfo",
1117 Arguments: []graphb.Argument{graphb.ArgumentCustomType("params", paramsArgs...)},
1118 Fields: graphb.Fields("readme", "metadata"),
1119 },
1120 },
1121 })
1122 }
1123
1124 func helmReleasesStatusQuery(clusterEdgeID string) string {
1125 return MustParse(graphb.Query{
1126 Type: graphb.TypeQuery,
1127 Fields: []*graphb.Field{
1128 {
1129 Name: "helmReleasesStatus",
1130 Arguments: []graphb.Argument{
1131 graphb.ArgumentString("clusterEdgeId", clusterEdgeID),
1132 },
1133 Fields: []*graphb.Field{
1134 graphb.NewField("configValues"),
1135 graphb.NewField("lastActionTime"),
1136 graphb.NewField("name"),
1137 graphb.NewField("statusType"),
1138 graphb.NewField("versionInstalled"),
1139 graphb.NewField("versionRequested"),
1140 {
1141 Name: "installCondition",
1142 Fields: graphb.Fields("installed", "lastTransitionTime", "ready", "message", "reason", "status", "type"),
1143 },
1144 {
1145 Name: "readyCondition",
1146 Fields: graphb.Fields("installed", "lastTransitionTime", "message", "ready", "reason", "status", "type"),
1147 },
1148 },
1149 },
1150 },
1151 })
1152 }
1153
1154 func helmChartVersionQuery(name, secretName, bannerEdgeID string) string {
1155 return MustParse(graphb.Query{
1156 Type: graphb.TypeQuery,
1157 Fields: []*graphb.Field{
1158 {
1159 Name: "helmChartVersion",
1160 Arguments: []graphb.Argument{
1161 graphb.ArgumentString("name", name),
1162 graphb.ArgumentString("secretName", secretName),
1163 graphb.ArgumentString("bannerEdgeId", bannerEdgeID),
1164 },
1165 Fields: graphb.Fields("name", "versions"),
1166 },
1167 },
1168 })
1169 }
1170
1171 func updateHelmReleaseMutation(helmEdgeID, clusterEdgeID, helmReleaseName, version, configValues string, secrets, labelEdgeIDs []string) string {
1172 args := []graphb.Argument{
1173 graphb.ArgumentString("helmEdgeId", helmEdgeID),
1174 graphb.ArgumentString("clusterEdgeId", clusterEdgeID),
1175 graphb.ArgumentString("helmReleaseName", helmReleaseName),
1176 }
1177 if version != "" {
1178 args = append(args, graphb.ArgumentString("version", version))
1179 }
1180 if configValues != "" {
1181 args = append(args, graphb.ArgumentString("configValues", configValues))
1182 }
1183 if secrets != nil {
1184 args = append(args, graphb.ArgumentStringSlice("secrets", secrets...))
1185 }
1186 if labelEdgeIDs != nil {
1187 args = append(args, graphb.ArgumentStringSlice("labelEdgeIds", labelEdgeIDs...))
1188 }
1189
1190 return MustParse(graphb.Query{
1191 Type: graphb.TypeMutation,
1192 Fields: []*graphb.Field{
1193 {
1194 Name: "updateHelmRelease",
1195 Arguments: args,
1196 },
1197 },
1198 })
1199 }
1200
1201 func deleteHelmReleaseMutation(helmEdgeID, clusterEdgeID, name string) string {
1202 var args = []graphb.Argument{
1203 graphb.ArgumentString("helmEdgeId", helmEdgeID),
1204 graphb.ArgumentString("clusterEdgeId", clusterEdgeID),
1205 graphb.ArgumentString("name", name),
1206 }
1207 return MustParse(graphb.Query{
1208 Type: graphb.TypeMutation,
1209 Fields: []*graphb.Field{
1210 {
1211 Name: "deleteHelmRelease",
1212 Arguments: args,
1213 },
1214 },
1215 })
1216 }
1217
1218
1219 func createHelmReleaseResources(hr *helmApi.HelmRelease) error {
1220 namespace := hr.Spec.TargetNamespace
1221 name := hr.Name
1222 httpPort := intstr.FromInt(8000)
1223 dep := mapper.GetTestWorkloadDeployment(httpPort)
1224 ss := mapper.GetTestWorkloadStatefulSet(httpPort)
1225 ds := mapper.GetTestWorkloadDaemonSet(httpPort)
1226
1227 releaseName := fmt.Sprintf("%s-%s", namespace, name)
1228 dep.Namespace = namespace
1229 dep.Name = name
1230 dep.Annotations["meta.helm.sh/release-name"] = releaseName
1231
1232 ss.Namespace = namespace
1233 ss.Name = name
1234 ss.Annotations["meta.helm.sh/release-name"] = releaseName
1235
1236 ds.Namespace = namespace
1237 ds.Name = name
1238 ds.Annotations["meta.helm.sh/release-name"] = releaseName
1239
1240 if err := runtimeClient.Create(context.Background(), dep); err != nil {
1241 return err
1242 }
1243 if err := runtimeClient.Create(context.Background(), ss); err != nil {
1244 return err
1245 }
1246 return runtimeClient.Create(context.Background(), ds)
1247 }
1248
1249 func addWorkloadLabelsMutation(helmEdgeID string, labelEdgeIDs []string) string {
1250 args := []graphb.Argument{
1251 graphb.ArgumentString("helmEdgeId", helmEdgeID),
1252 }
1253 if labelEdgeIDs != nil {
1254 args = append(args, graphb.ArgumentStringSlice("labelEdgeIds", labelEdgeIDs...))
1255 }
1256 return MustParse(graphb.Query{
1257 Type: graphb.TypeMutation,
1258 Fields: []*graphb.Field{
1259 {
1260 Name: "addWorkloadLabels",
1261 Arguments: args,
1262 },
1263 },
1264 })
1265 }
1266
1267 func deleteWorkloadLabelMutation(helmEdgeID string, labelEdgeID string) string {
1268 workloadLabelParams := graphb.ArgumentCustomTypeSliceElem(
1269 graphb.ArgumentString("helmEdgeId", helmEdgeID),
1270 graphb.ArgumentString("labelEdgeId", labelEdgeID),
1271 )
1272 args := []graphb.Argument{
1273 graphb.ArgumentCustomType("workloadLabelParameters", workloadLabelParams...),
1274 }
1275
1276 return MustParse(graphb.Query{
1277 Type: graphb.TypeMutation,
1278 Fields: []*graphb.Field{
1279 {
1280 Name: "deleteWorkloadLabel",
1281 Arguments: args,
1282 },
1283 },
1284 })
1285 }
1286
1287
1288
1289 func (s Suite) getHelmEdgeIDByNameAndID(ctx context.Context, helmReleaseName string, clusterEdgeID, bannerEdgeID *string) (string, error) {
1290 var (
1291 helmEdgeID string
1292 row *sql.Row
1293 )
1294
1295 if !utils.IsNullOrEmpty(bannerEdgeID) {
1296 row = s.DB.QueryRowContext(ctx, sqlquery.GetHelmEdgeIDByNameAndBannerEdgeID, helmReleaseName, bannerEdgeID)
1297 } else if !utils.IsNullOrEmpty(clusterEdgeID) {
1298 row = s.DB.QueryRowContext(ctx, sqlquery.GetHelmEdgeIDByNameAndClusterEdgeID, helmReleaseName, clusterEdgeID)
1299 } else {
1300 return "", apierror.New("please provide clusterEdgeId or bannerEdgeId")
1301 }
1302
1303 if err := row.Scan(&helmEdgeID); err != nil {
1304 return "", fmt.Errorf("failed to get helmEdgeID for workload: %w", err)
1305 }
1306 return helmEdgeID, nil
1307 }
1308
View as plain text