Skip to content

Commit f9e695a

Browse files
committed
chore: add tests for secret updation behavior
1 parent 3679188 commit f9e695a

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

test/e2e/reconcile_objects_test.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package e2e
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"slices"
7+
"strings"
8+
"testing"
9+
"time"
10+
11+
"github.com/openshift/cluster-monitoring-operator/test/e2e/framework"
12+
"github.com/stretchr/testify/require"
13+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
"k8s.io/apimachinery/pkg/types"
15+
)
16+
17+
// TestSecretsReconciliation tests whether the secrets created by the operator are reconciled correctly. These include:
18+
// * unsynced secrets: secrets that are deployed by, but not synced by the operator, and,
19+
// * synced secrets: secrets that are deployed by, and should be synced by the operator.
20+
func TestSecretsReconciliation(t *testing.T) {
21+
// Create assets under both scenarios for us to work with.
22+
setupUserWorkloadAssetsWithTeardownHook(t, f)
23+
userWorkloadConfigMap := f.BuildUserWorkloadConfigMap(t, `alertmanager:
24+
enabled: true
25+
`)
26+
f.MustCreateOrUpdateConfigMap(t, userWorkloadConfigMap)
27+
defer f.MustDeleteConfigMap(t, userWorkloadConfigMap)
28+
29+
// List of secrets that should not be synced during operator's reconciliation.
30+
unsyncedSecrets := []types.NamespacedName{
31+
{
32+
Name: "alertmanager-main",
33+
Namespace: f.Ns,
34+
},
35+
{
36+
Name: "alertmanager-user-workload",
37+
Namespace: f.UserWorkloadMonitoringNs,
38+
},
39+
}
40+
41+
// Restore all unsynced secrets to their original state.
42+
cleanup := func() {
43+
for _, secret := range unsyncedSecrets {
44+
gotSecret, err := f.KubeClient.CoreV1().Secrets(secret.Namespace).Get(context.Background(), secret.Name, metav1.GetOptions{})
45+
require.NoError(t, err)
46+
data := gotSecret.Data
47+
stringData := gotSecret.StringData
48+
for k, v := range data {
49+
data[k] = []byte(strings.TrimPrefix(string(v), t.Name()))
50+
}
51+
for k, v := range stringData {
52+
stringData[k] = strings.TrimPrefix(v, t.Name())
53+
}
54+
_, err = f.KubeClient.CoreV1().Secrets(secret.Namespace).Update(context.Background(), gotSecret, metav1.UpdateOptions{})
55+
require.NoError(t, err)
56+
}
57+
}
58+
defer cleanup()
59+
60+
var syncedSecrets []types.NamespacedName
61+
secretsNS, err := f.KubeClient.CoreV1().Secrets(f.Ns).List(context.Background(), metav1.ListOptions{
62+
// Intentionally commented out as we want to fetch all secrets.
63+
// LabelSelector: "app.kubernetes.io/managed-by=cluster-monitoring-operator",
64+
})
65+
require.NoError(t, err)
66+
secretsUWMNS, err := f.KubeClient.CoreV1().Secrets(f.UserWorkloadMonitoringNs).List(context.Background(), metav1.ListOptions{
67+
// Intentionally commented out as we want to fetch all secrets.
68+
// LabelSelector: "app.kubernetes.io/managed-by=cluster-monitoring-operator",
69+
})
70+
require.NoError(t, err)
71+
for _, secret := range append(secretsNS.Items, secretsUWMNS.Items...) {
72+
secretNamespacedName := types.NamespacedName{
73+
Name: secret.Name,
74+
Namespace: secret.Namespace,
75+
}
76+
if slices.Contains(unsyncedSecrets, secretNamespacedName) {
77+
continue
78+
}
79+
syncedSecrets = append(syncedSecrets, secretNamespacedName)
80+
}
81+
require.NotEmpty(t, syncedSecrets)
82+
83+
// Update the aforementioned secrets' data.
84+
secrets := append(syncedSecrets, unsyncedSecrets...)
85+
for _, secret := range secrets {
86+
gotSecret, err := f.KubeClient.CoreV1().Secrets(secret.Namespace).Get(context.Background(), secret.Name, metav1.GetOptions{})
87+
require.NoError(t, err)
88+
data := gotSecret.Data
89+
stringData := gotSecret.StringData
90+
for k, v := range data {
91+
data[k] = []byte(t.Name() + string(v))
92+
break
93+
}
94+
for k, v := range stringData {
95+
stringData[k] = t.Name() + v
96+
break
97+
}
98+
_, err = f.KubeClient.CoreV1().Secrets(secret.Namespace).Update(context.Background(), gotSecret, metav1.UpdateOptions{})
99+
require.NoError(t, err)
100+
101+
// Check if the secrets were reconciled as expected.
102+
if slices.Contains(syncedSecrets, secret) {
103+
err := framework.Poll(time.Second, 6*time.Minute, func() error {
104+
updatedSecret, err := f.KubeClient.CoreV1().Secrets(secret.Namespace).Get(context.Background(), secret.Name, metav1.GetOptions{})
105+
if err != nil {
106+
return err
107+
}
108+
data := updatedSecret.Data
109+
stringData := updatedSecret.StringData
110+
for _, v := range data {
111+
if strings.HasPrefix(string(v), t.Name()) {
112+
return fmt.Errorf("secret %s has unexpected data", secret.String())
113+
}
114+
}
115+
for _, v := range stringData {
116+
if strings.HasPrefix(v, t.Name()) {
117+
return fmt.Errorf("secret %s has unexpected stringData", secret.String())
118+
}
119+
}
120+
return nil
121+
})
122+
require.NoError(t, err)
123+
}
124+
125+
// Check if the secrets were reconciled unexpectedly.
126+
if slices.Contains(unsyncedSecrets, secret) {
127+
updatedSecret, err := f.KubeClient.CoreV1().Secrets(secret.Namespace).Get(context.Background(), secret.Name, metav1.GetOptions{})
128+
require.NoError(t, err)
129+
for _, v := range updatedSecret.Data {
130+
require.False(t, strings.HasPrefix(string(v), t.Name()), fmt.Sprintf("secret %s was unexpectedly reconciled", secret.String()))
131+
}
132+
for _, v := range updatedSecret.StringData {
133+
require.False(t, strings.HasPrefix(v, t.Name()), fmt.Sprintf("secret %s was unexpectedly reconciled", secret.String()))
134+
}
135+
}
136+
}
137+
}

0 commit comments

Comments
 (0)