From 50800857b6aa2ccfec7d38135f162343bae2947c Mon Sep 17 00:00:00 2001 From: Zacharias Taubert Date: Sun, 14 Nov 2021 23:27:15 +0100 Subject: [PATCH] Append to list of ownerReferences for cm and secrets If a "primary" ConfigMap or Secret already exists, keep the list of ownerReferences and append the updating Canary as ownerReference if it's not already in the list. This will prevent the GC from deleting primary ConfigMaps and Secrets used by multiple primary deployments when one is deleted. Signed-off-by: Zacharias Taubert --- pkg/canary/config_tracker.go | 75 ++++++++++++++++++++++--------- pkg/canary/config_tracker_test.go | 24 ++++++++++ 2 files changed, 77 insertions(+), 22 deletions(-) diff --git a/pkg/canary/config_tracker.go b/pkg/canary/config_tracker.go index ecd16a76..c821312e 100644 --- a/pkg/canary/config_tracker.go +++ b/pkg/canary/config_tracker.go @@ -299,22 +299,38 @@ func (ct *ConfigTracker) CreatePrimaryConfigs(cd *flaggerv1.Canary, refs map[str case ConfigRefMap: config, err := ct.KubeClient.CoreV1().ConfigMaps(cd.Namespace).Get(context.TODO(), ref.Name, metav1.GetOptions{}) if err != nil { - return fmt.Errorf("configmap %s.%s get query failed : %w", ref.Name, cd.Name, err) + return fmt.Errorf("configmap %s.%s get query failed : %w", ref.Name, cd.Namespace, err) } primaryName := fmt.Sprintf("%s-primary", config.GetName()) + ownerReferences := []metav1.OwnerReference{ + *metav1.NewControllerRef(cd, schema.GroupVersionKind{ + Group: flaggerv1.SchemeGroupVersion.Group, + Version: flaggerv1.SchemeGroupVersion.Version, + Kind: flaggerv1.CanaryKind, + }), + } + + oldPrimary, err := ct.KubeClient.CoreV1().ConfigMaps(cd.Namespace).Get(context.TODO(), primaryName, metav1.GetOptions{}) + if err != nil { + if !errors.IsNotFound(err) { + return fmt.Errorf("configmap %s.%s get query failed : %w", primaryName, cd.Namespace, err) + } + } else { + for _, ownerRef := range oldPrimary.OwnerReferences { + if ownerRef.Kind != flaggerv1.CanaryKind || ownerRef.Name != cd.Name { + ownerRef.Controller = new(bool) + ownerReferences = append(ownerReferences, ownerRef) + } + } + } + labels := includeLabelsByPrefix(config.Labels, includeLabelPrefix) primaryConfigMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: primaryName, - Namespace: cd.Namespace, - Labels: labels, - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(cd, schema.GroupVersionKind{ - Group: flaggerv1.SchemeGroupVersion.Group, - Version: flaggerv1.SchemeGroupVersion.Version, - Kind: flaggerv1.CanaryKind, - }), - }, + Name: primaryName, + Namespace: cd.Namespace, + Labels: labels, + OwnerReferences: ownerReferences, }, Data: config.Data, } @@ -337,22 +353,37 @@ func (ct *ConfigTracker) CreatePrimaryConfigs(cd *flaggerv1.Canary, refs map[str case ConfigRefSecret: secret, err := ct.KubeClient.CoreV1().Secrets(cd.Namespace).Get(context.TODO(), ref.Name, metav1.GetOptions{}) if err != nil { - return fmt.Errorf("secret %s.%s get query failed : %w", ref.Name, cd.Name, err) + return fmt.Errorf("secret %s.%s get query failed : %w", ref.Name, cd.Namespace, err) } primaryName := fmt.Sprintf("%s-primary", secret.GetName()) + ownerReferences := []metav1.OwnerReference{ + *metav1.NewControllerRef(cd, schema.GroupVersionKind{ + Group: flaggerv1.SchemeGroupVersion.Group, + Version: flaggerv1.SchemeGroupVersion.Version, + Kind: flaggerv1.CanaryKind, + }), + } + + oldPrimary, err := ct.KubeClient.CoreV1().Secrets(cd.Namespace).Get(context.TODO(), primaryName, metav1.GetOptions{}) + if err != nil { + if !errors.IsNotFound(err) { + return fmt.Errorf("secret %s.%s get query failed : %w", primaryName, cd.Namespace, err) + } + } else { + for _, ownerRef := range oldPrimary.OwnerReferences { + if ownerRef.Kind != flaggerv1.CanaryKind || ownerRef.Name != cd.Name { + ownerRef.Controller = new(bool) + ownerReferences = append(ownerReferences, ownerRef) + } + } + } labels := includeLabelsByPrefix(secret.Labels, includeLabelPrefix) primarySecret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: primaryName, - Namespace: cd.Namespace, - Labels: labels, - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(cd, schema.GroupVersionKind{ - Group: flaggerv1.SchemeGroupVersion.Group, - Version: flaggerv1.SchemeGroupVersion.Version, - Kind: flaggerv1.CanaryKind, - }), - }, + Name: primaryName, + Namespace: cd.Namespace, + Labels: labels, + OwnerReferences: ownerReferences, }, Type: secret.Type, Data: secret.Data, diff --git a/pkg/canary/config_tracker_test.go b/pkg/canary/config_tracker_test.go index 2134a5f6..cc2ebab4 100644 --- a/pkg/canary/config_tracker_test.go +++ b/pkg/canary/config_tracker_test.go @@ -399,3 +399,27 @@ func Test_fieldIsMandatory(t *testing.T) { assert.Equal(t, tt.expected, actual) } } + +func TestConfigTracker_ConfigOwnerMultiDeployment(t *testing.T) { + t.Run("deployment", func(t *testing.T) { + dc := deploymentConfigs{name: "podinfo", label: "name", labelValue: "podinfo"} + mocks := newDeploymentFixture(dc) + mocks.initializeCanary(t) + + dep := newDeploymentControllerTest(dc) + dep.Name = "podinfo2" + canary := newDeploymentControllerTestCanary(canaryConfigs{targetName: "podinfo2"}) + canary.Name = "podinfo2" + canary.Spec.TargetRef.Name = dep.Name + mocks.kubeClient.AppsV1().Deployments("default").Create(context.TODO(), dep, metav1.CreateOptions{}) + mocks.controller.Initialize(canary) + + configMapPrimary, err := mocks.kubeClient.CoreV1().ConfigMaps("default").Get(context.TODO(), "podinfo-config-env-primary", metav1.GetOptions{}) + require.NoError(t, err) + assert.Len(t, configMapPrimary.OwnerReferences, 2) + + secretPrimary, err := mocks.kubeClient.CoreV1().Secrets("default").Get(context.TODO(), "podinfo-secret-env-primary", metav1.GetOptions{}) + require.NoError(t, err) + assert.Len(t, secretPrimary.OwnerReferences, 2) + }) +}