Skip to content

Commit cfd4a21

Browse files
Merge pull request #370 from pat-cremin/main
MTSRE-1214 Add sendgrid credentials to package config
2 parents d45d764 + d245686 commit cfd4a21

3 files changed

Lines changed: 151 additions & 58 deletions

File tree

integration/helpers.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func InitOCMClient() error {
125125
ocmClient, err := ocm.NewClient(
126126
context.Background(),
127127
ocm.WithEndpoint("http://127.0.0.1:8001/api/v1/namespaces/api-mock/services/api-mock:80/proxy"),
128-
ocm.WithAccessToken("accessToken"), //TODO: Needs to be supplied from the outside, does not matter for mock.
128+
ocm.WithAccessToken("accessToken"), // TODO: Needs to be supplied from the outside, does not matter for mock.
129129
ocm.WithClusterExternalID(string(Cv.Spec.ClusterID)),
130130
)
131131
if err != nil {
@@ -212,6 +212,15 @@ func WaitForObject(
212212
t *testing.T, timeout time.Duration,
213213
object client.Object, reason string,
214214
checkFn func(obj client.Object) (done bool, err error),
215+
) error {
216+
return WaitForObjectWithInterval(ctx, t, time.Second, timeout, object, reason, checkFn)
217+
}
218+
219+
func WaitForObjectWithInterval(
220+
ctx context.Context,
221+
t *testing.T, interval time.Duration, timeout time.Duration,
222+
object client.Object, reason string,
223+
checkFn func(obj client.Object) (done bool, err error),
215224
) error {
216225
gvk, err := apiutil.GVKForObject(object, Scheme)
217226
if err != nil {
@@ -222,7 +231,7 @@ func WaitForObject(
222231
t.Logf("waiting %s on %s %s %s...",
223232
timeout, gvk, key, reason)
224233

225-
return wait.PollImmediate(time.Second, timeout, func() (done bool, err error) {
234+
return wait.PollImmediate(interval, timeout, func() (done bool, err error) {
226235
err = Client.Get(ctx, client.ObjectKeyFromObject(object), object)
227236
if err != nil {
228237
//nolint:nilerr // retry on transient errors

integration/pko_test.go

Lines changed: 124 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"fmt"
77
"sort"
88
"strings"
9+
"sync"
10+
"time"
911

1012
"github.com/go-logr/logr"
1113
"github.com/google/uuid"
@@ -32,10 +34,10 @@ const (
3234
deadMansSnitchUrlValue = "https://example.com/test-snitch-url"
3335
pagerDutyKeyValue = "1234567890ABCDEF"
3436

35-
// source: https://github.com/kostola/package-operator-packages/tree/v3.0/openshift/addon-operator/apnp-test-optional-params
36-
pkoImageOptionalParams = "quay.io/alcosta/package-operator-packages/openshift/addon-operator/apnp-test-optional-params:v3.0"
37-
// source: https://github.com/kostola/package-operator-packages/tree/v3.0/openshift/addon-operator/apnp-test-required-params
38-
pkoImageRequiredParams = "quay.io/alcosta/package-operator-packages/openshift/addon-operator/apnp-test-required-params:v3.0"
37+
// source: https://github.com/kostola/package-operator-packages/tree/v4.0/openshift/addon-operator/apnp-test-optional-params
38+
pkoImageOptionalParams = "quay.io/alcosta/package-operator-packages/openshift/addon-operator/apnp-test-optional-params:v4.0"
39+
// source: https://github.com/kostola/package-operator-packages/tree/v4.0/openshift/addon-operator/apnp-test-required-params
40+
pkoImageRequiredParams = "quay.io/alcosta/package-operator-packages/openshift/addon-operator/apnp-test-required-params:v4.0"
3941
)
4042

4143
func (s *integrationTestSuite) TestPackageOperatorReconcilerStatusPropagatedToAddon() {
@@ -136,6 +138,7 @@ type TestPKOSourcesData struct {
136138
deployAddonParametersSecret bool
137139
deployDeadMansSnitchSecret bool
138140
deployPagerDutySecret bool
141+
deploySendGridSecret bool
139142
clusterPackageStatus string
140143
}
141144

@@ -160,70 +163,114 @@ func (s *integrationTestSuite) TestPackageOperatorReconcilerSourceParameterInjec
160163
"PdN": false,
161164
"PdY": true,
162165
}
166+
sgValues := map[string]bool{
167+
"SgN": false,
168+
"SgY": true,
169+
}
163170

164171
// create all combinations
165172
var tests []TestPKOSourcesData
166173
for parK, parV := range parValues {
167174
for apK, apV := range apValues {
168175
for dsK, dsV := range dsValues {
169176
for pdK, pdV := range pdValues {
170-
pkoImage := pkoImageOptionalParams
171-
if parV {
172-
pkoImage = pkoImageRequiredParams
173-
}
174-
175-
status := v1alpha1.PackageAvailable
176-
if parV && (!apV || !dsV || !pdV) {
177-
status = pkov1alpha1.PackageInvalid
177+
for sgK, sgV := range sgValues {
178+
pkoImage := pkoImageOptionalParams
179+
if parV {
180+
pkoImage = pkoImageRequiredParams
181+
}
182+
183+
status := v1alpha1.PackageAvailable
184+
if parV && (!apV || !dsV || !pdV || !sgV) {
185+
status = pkov1alpha1.PackageInvalid
186+
}
187+
188+
tests = append(tests, TestPKOSourcesData{
189+
fmt.Sprintf("%s%s%s%s%s", parK, apK, dsK, pdK, sgK),
190+
fmt.Sprintf("%s-%s-%s-%s-%s", strings.ToLower(parK), strings.ToLower(apK), strings.ToLower(dsK), strings.ToLower(pdK), strings.ToLower(sgK)),
191+
parV, pkoImage,
192+
apV, dsV, pdV, sgV,
193+
status,
194+
})
178195
}
179-
180-
tests = append(tests, TestPKOSourcesData{
181-
fmt.Sprintf("%s%s%s%s", parK, apK, dsK, pdK),
182-
fmt.Sprintf("%s-%s-%s-%s", strings.ToLower(parK), strings.ToLower(apK), strings.ToLower(dsK), strings.ToLower(pdK)),
183-
parV, pkoImage,
184-
apV, dsV, pdV,
185-
status,
186-
})
187196
}
188197
}
189198
}
190199
}
191-
192200
sort.Slice(tests, func(i, j int) bool {
193201
return tests[i].name < tests[j].name
194202
})
195203

196-
for index, test := range tests {
197-
s.Run(test.name, func() {
198-
testAddonName := fmt.Sprintf("%s-%02d-%s", addonName, index, test.resourceSuffix)
199-
testAddonNamespace := fmt.Sprintf("%s-%02d-%s", addonNamespace, index, test.resourceSuffix)
200-
ctx := context.Background()
204+
// number of parallel workers
205+
numWorkers := 8
206+
// create a WaitGroup to wait for all jobs to finish
207+
var wg sync.WaitGroup
208+
// set the WaitGroup counter to the total number of jobs
209+
wg.Add(len(tests))
210+
// launch workers
211+
for i := 0; i < numWorkers; i++ {
212+
go testWorker(s, i, numWorkers, &wg, tests)
213+
}
214+
// wait for all jobs to finish
215+
timedOut := waitTimeout(&wg, 15*time.Minute)
216+
// check that the timeout didn't trigger
217+
s.Require().False(timedOut)
218+
}
201219

202-
addon := s.createAddon(ctx, testAddonName, testAddonNamespace, test.pkoImage)
203-
s.waitForNamespace(ctx, testAddonNamespace)
220+
func testWorker(s *integrationTestSuite, workerID int, numWorkers int, wg *sync.WaitGroup, testSources []TestPKOSourcesData) {
221+
testIdx := workerID
204222

205-
if test.deployAddonParametersSecret {
206-
s.createAddonParametersSecret(ctx, testAddonName, testAddonNamespace)
207-
}
208-
if test.deployDeadMansSnitchSecret {
209-
s.createDeadMansSnitchSecret(ctx, testAddonName, testAddonNamespace)
210-
}
211-
if test.deployPagerDutySecret {
212-
s.createPagerDutySecret(ctx, testAddonName, testAddonNamespace)
213-
}
223+
for counter := 1; testIdx < len(testSources); counter++ {
224+
testSource := testSources[testIdx]
214225

215-
s.waitForClusterPackage(
216-
ctx,
217-
testAddonName,
218-
testAddonNamespace,
219-
test.clusterPackageStatus,
220-
test.deployAddonParametersSecret,
221-
test.deployDeadMansSnitchSecret,
222-
test.deployPagerDutySecret,
223-
)
224-
225-
s.T().Cleanup(func() { s.addonCleanup(addon, ctx) })
226-
})
226+
testAddonName := fmt.Sprintf("%s-%02d-%s", addonName, testIdx, testSource.resourceSuffix)
227+
testAddonNamespace := fmt.Sprintf("%s-%02d-%s", addonNamespace, testIdx, testSource.resourceSuffix)
228+
ctx := context.Background()
229+
230+
addon := s.createAddon(ctx, testAddonName, testAddonNamespace, testSource.pkoImage)
231+
s.waitForNamespace(ctx, testAddonNamespace)
232+
233+
if testSource.deployAddonParametersSecret {
234+
s.createAddonParametersSecret(ctx, testAddonName, testAddonNamespace)
235+
}
236+
if testSource.deployDeadMansSnitchSecret {
237+
s.createDeadMansSnitchSecret(ctx, testAddonName, testAddonNamespace)
238+
}
239+
if testSource.deployPagerDutySecret {
240+
s.createPagerDutySecret(ctx, testAddonName, testAddonNamespace)
241+
}
242+
if testSource.deploySendGridSecret {
243+
s.createSendGridSecret(ctx, testAddonName, testAddonNamespace)
244+
}
245+
246+
s.waitForClusterPackage(
247+
ctx,
248+
testAddonName,
249+
testAddonNamespace,
250+
testSource.clusterPackageStatus,
251+
testSource.deployAddonParametersSecret,
252+
testSource.deployDeadMansSnitchSecret,
253+
testSource.deployPagerDutySecret,
254+
testSource.deploySendGridSecret,
255+
)
256+
257+
s.addonCleanup(addon, ctx)
258+
wg.Done()
259+
testIdx = workerID + counter*numWorkers
260+
}
261+
}
262+
263+
func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {
264+
c := make(chan struct{})
265+
go func() {
266+
defer close(c)
267+
wg.Wait()
268+
}()
269+
select {
270+
case <-c:
271+
return false // completed normally
272+
case <-time.After(timeout):
273+
return true // timed out
227274
}
228275
}
229276

@@ -282,6 +329,12 @@ func (s *integrationTestSuite) createPagerDutySecret(ctx context.Context, addonN
282329
s.createSecret(ctx, addonName+"-pagerduty", addonNamespace, map[string][]byte{"PAGERDUTY_KEY": []byte(pagerDutyKeyValue)})
283330
}
284331

332+
// create the Secret resource for SendGrid as defined here:
333+
// - https://mt-sre.github.io/docs/creating-addons/monitoring/ocm_sendgrid_service_integration/
334+
func (s *integrationTestSuite) createSendGridSecret(ctx context.Context, addonName string, addonNamespace string) {
335+
s.createSecret(ctx, addonName+"-smtp", addonNamespace, map[string][]byte{"host": []byte("clusterID"), "password": []byte("pwd"), "port": []byte("1111"), "tls": []byte("true"), "username": []byte("user")})
336+
}
337+
285338
func (s *integrationTestSuite) createSecret(ctx context.Context, name string, namespace string, data map[string][]byte) {
286339
secret := &v1.Secret{
287340
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace},
@@ -294,13 +347,13 @@ func (s *integrationTestSuite) createSecret(ctx context.Context, name string, na
294347
// wait until all the replicas in the Deployment inside the ClusterPackage are ready
295348
// and check if their env variables corresponds to the secrets
296349
func (s *integrationTestSuite) waitForClusterPackage(ctx context.Context, addonName string, addonNamespace string, conditionType string,
297-
addonParametersValuePresent bool, deadMansSnitchUrlValuePresent bool, pagerDutyValuePresent bool,
350+
addonParametersValuePresent bool, deadMansSnitchUrlValuePresent bool, pagerDutyValuePresent bool, sendGridValuePresent bool,
298351
) {
299352
logger := testutil.NewLogger(s.T())
300353
cp := &v1alpha1.ClusterPackage{ObjectMeta: metav1.ObjectMeta{Name: addonName}}
301-
err := integration.WaitForObject(ctx, s.T(),
354+
err := integration.WaitForObjectWithInterval(ctx, s.T(), 20*time.Second,
302355
defaultAddonAvailabilityTimeout, cp, "to be "+conditionType,
303-
clusterPackageChecker(&logger, addonNamespace, conditionType, addonParametersValuePresent, deadMansSnitchUrlValuePresent, pagerDutyValuePresent))
356+
clusterPackageChecker(&logger, addonNamespace, conditionType, addonParametersValuePresent, deadMansSnitchUrlValuePresent, pagerDutyValuePresent, sendGridValuePresent))
304357
s.Require().NoError(err)
305358
}
306359

@@ -311,6 +364,7 @@ func clusterPackageChecker(
311364
addonParametersValuePresent bool,
312365
deadMansSnitchUrlValuePresent bool,
313366
pagerDutyValuePresent bool,
367+
sendGridValuePresent bool,
314368
) func(client.Object) (done bool, err error) {
315369
if conditionType == v1alpha1.PackageInvalid {
316370
return func(obj client.Object) (done bool, err error) {
@@ -361,7 +415,7 @@ func clusterPackageChecker(
361415
ocmClusterName, present := addonsv1[addon.OcmClusterNameConfigKey]
362416
ocmClusterNameValueOk := present && len(fmt.Sprintf("%v", ocmClusterName)) > 0
363417

364-
addonParametersValueOk, deadMansSnitchUrlValueOk, pagerDutyValueOk := false, false, false
418+
addonParametersValueOk, deadMansSnitchUrlValueOk, pagerDutyValueOk, sendGridValueOk := false, false, false, false
365419
if addonParametersValuePresent {
366420
value, present := addonsv1[addon.ParametersConfigKey]
367421
if present {
@@ -388,23 +442,37 @@ func clusterPackageChecker(
388442
_, present := addonsv1[addon.PagerDutyKeyConfigKey]
389443
pagerDutyValueOk = !present
390444
}
445+
if sendGridValuePresent {
446+
value, present := addonsv1[addon.SendGridConfigKey]
447+
if present {
448+
jsonValue, err := json.Marshal(value)
449+
if err == nil {
450+
sendGridValueOk = string(jsonValue) == "{\"host\":\"clusterID\",\"password\":\"pwd\",\"port\":\"1111\",\"tls\":\"true\",\"username\":\"user\"}"
451+
}
452+
}
453+
} else {
454+
_, present := addonsv1[addon.SendGridConfigKey]
455+
sendGridValueOk = !present
456+
}
391457

392-
logger.Info(fmt.Sprintf("targetNamespace=%t, clusterID=%t, ocmClusterID=%t, ocmClusterName=%t, addonParameters=%t, deadMansSnitchUrl=%t, pagerDutyKey=%t",
458+
logger.Info(fmt.Sprintf("targetNamespace=%t, clusterID=%t, ocmClusterID=%t, ocmClusterName=%t, addonParameters=%t, deadMansSnitchUrl=%t, pagerDutyKey=%t, sendGrid=%t",
393459
targetNamespaceValueOk,
394460
clusterIDValueOk,
395461
ocmClusterIDValueOk,
396462
ocmClusterNameValueOk,
397463
addonParametersValueOk,
398464
deadMansSnitchUrlValueOk,
399-
pagerDutyValueOk))
465+
pagerDutyValueOk,
466+
sendGridValueOk))
400467

401468
result := targetNamespaceValueOk &&
402469
clusterIDValueOk &&
403470
ocmClusterIDValueOk &&
404471
ocmClusterNameValueOk &&
405472
addonParametersValueOk &&
406473
deadMansSnitchUrlValueOk &&
407-
pagerDutyValueOk
474+
pagerDutyValueOk &&
475+
sendGridValueOk
408476

409477
logger.Info(fmt.Sprintf("result: %t", result))
410478
return result, nil

internal/controllers/addon/package_operator_reconciler.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ spec:
3030
merge
3131
(.config | b64decMap)
3232
(hasKey .config "%[4]s" | ternary (dict "%[4]s" (index .config "%[4]s" | b64decMap)) (dict))
33+
(hasKey .config "%[13]s" | ternary (dict "%[13]s" (index .config "%[13]s" | b64decMap)) (dict))
3334
(dict "%[5]s" "%[6]s" "%[7]s" "%[8]s" "%[9]s" "%[10]s" "%[11]s" "%[12]s")
3435
)}}
3536
`
@@ -43,6 +44,7 @@ const (
4344
PagerDutyKeyConfigKey = "pagerDutyKey"
4445
ParametersConfigKey = "parameters"
4546
TargetNamespaceConfigKey = "targetNamespace"
47+
SendGridConfigKey = "smtp"
4648
)
4749

4850
type OcmClusterInfo struct {
@@ -88,6 +90,7 @@ func (r *PackageOperatorReconciler) reconcileClusterObjectTemplate(ctx context.C
8890
OcmClusterIDConfigKey, ocmClusterInfo.ID,
8991
OcmClusterNameConfigKey, ocmClusterInfo.Name,
9092
TargetNamespaceConfigKey, addonDestNamespace,
93+
SendGridConfigKey,
9194
)
9295

9396
clusterObjectTemplate := &pkov1alpha1.ClusterObjectTemplate{
@@ -136,6 +139,19 @@ func (r *PackageOperatorReconciler) reconcileClusterObjectTemplate(ctx context.C
136139
},
137140
},
138141
},
142+
{
143+
Optional: true,
144+
APIVersion: "v1",
145+
Kind: "Secret",
146+
Name: addon.Name + "-smtp",
147+
Namespace: addonDestNamespace,
148+
Items: []pkov1alpha1.ObjectTemplateSourceItem{
149+
{
150+
Key: ".data",
151+
Destination: "." + SendGridConfigKey,
152+
},
153+
},
154+
},
139155
},
140156
},
141157
}

0 commit comments

Comments
 (0)