diff --git a/docs/content/addons/cni.md b/docs/content/addons/cni.md index 1a8f509a1..b562219b0 100644 --- a/docs/content/addons/cni.md +++ b/docs/content/addons/cni.md @@ -75,8 +75,6 @@ data: mode: kubernetes kind: ConfigMap metadata: - labels: - clusterctl.cluster.x-k8s.io/move: "" name: -cilium-cni-helm-values-template namespace: ``` diff --git a/pkg/handlers/generic/lifecycle/ccm/nutanix/handler.go b/pkg/handlers/generic/lifecycle/ccm/nutanix/handler.go index 4c9b12fc9..1fd287e1b 100644 --- a/pkg/handlers/generic/lifecycle/ccm/nutanix/handler.go +++ b/pkg/handlers/generic/lifecycle/ccm/nutanix/handler.go @@ -13,6 +13,7 @@ import ( "github.com/go-logr/logr" "github.com/spf13/pflag" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -84,10 +85,13 @@ func (p *provider) Apply( // However, that would leave the credentials visible in the HelmChartProxy. // Instead, we'll create the Secret on the remote cluster and reference it in the Helm values. if clusterConfig.Addons.CCM.Credentials != nil { - err := handlersutils.EnsureOwnerReferenceForSecret( + err := handlersutils.EnsureClusterOwnerReferenceForObject( ctx, p.client, - clusterConfig.Addons.CCM.Credentials.SecretRef.Name, + corev1.TypedLocalObjectReference{ + Kind: "Secret", + Name: clusterConfig.Addons.CCM.Credentials.SecretRef.Name, + }, cluster, ) if err != nil { diff --git a/pkg/handlers/generic/lifecycle/cni/cilium/handler.go b/pkg/handlers/generic/lifecycle/cni/cilium/handler.go index 3ace8ce26..9a19ad971 100644 --- a/pkg/handlers/generic/lifecycle/cni/cilium/handler.go +++ b/pkg/handlers/generic/lifecycle/cni/cilium/handler.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/spf13/pflag" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -22,6 +23,7 @@ import ( "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/addons" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" + handlersutils "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/utils" ) type CNIConfig struct { @@ -183,6 +185,33 @@ func (c *CiliumCNI) apply( helmValuesSourceRefName = cniVar.Values.SourceRef.Name // Use cluster's namespace since Values.SourceRef is always a LocalObjectReference targetNamespace = cluster.Namespace + + err := handlersutils.EnsureClusterOwnerReferenceForObject( + ctx, + c.client, + corev1.TypedLocalObjectReference{ + Kind: cniVar.Values.SourceRef.Kind, + Name: cniVar.Values.SourceRef.Name, + }, + cluster, + ) + if err != nil { + log.Error( + err, + "error updating Cluster's owner reference on Cilium helm values source object", + "name", + cniVar.Values.SourceRef.Name, + "kind", + cniVar.Values.SourceRef.Kind, + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf( + "failed to set Cluster's owner reference on Cilium helm values source object: %v", + err, + ), + ) + } } strategy = addons.NewHelmAddonApplier( diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix/handler.go index 571bafd68..2a1752b22 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix/handler.go @@ -9,6 +9,7 @@ import ( "github.com/go-logr/logr" "github.com/spf13/pflag" + corev1 "k8s.io/api/core/v1" "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -108,10 +109,13 @@ func (n *NutanixCSI) Apply( } if provider.Credentials != nil { - err := handlersutils.EnsureOwnerReferenceForSecret( + err := handlersutils.EnsureClusterOwnerReferenceForObject( ctx, n.client, - provider.Credentials.SecretRef.Name, + corev1.TypedLocalObjectReference{ + Kind: "Secret", + Name: provider.Credentials.SecretRef.Name, + }, cluster, ) if err != nil { diff --git a/pkg/handlers/generic/mutation/imageregistries/credentials/inject.go b/pkg/handlers/generic/mutation/imageregistries/credentials/inject.go index c5daa175a..dcd59bda1 100644 --- a/pkg/handlers/generic/mutation/imageregistries/credentials/inject.go +++ b/pkg/handlers/generic/mutation/imageregistries/credentials/inject.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" + corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -287,10 +288,13 @@ func ensureOwnerReferenceOnCredentialsSecrets( if secretName := handlersutils.SecretNameForImageRegistryCredentials(credential); secretName != "" { // Ensure the Secret is owned by the Cluster so it is correctly moved and deleted with the Cluster. // This code assumes that Secret exists and that was validated before calling this function. - err := handlersutils.EnsureOwnerReferenceForSecret( + err := handlersutils.EnsureClusterOwnerReferenceForObject( ctx, c, - secretName, + corev1.TypedLocalObjectReference{ + Kind: "Secret", + Name: secretName, + }, cluster, ) if err != nil { diff --git a/pkg/handlers/utils/secrets.go b/pkg/handlers/utils/secrets.go index de5200199..ec1c129ae 100644 --- a/pkg/handlers/utils/secrets.go +++ b/pkg/handlers/utils/secrets.go @@ -9,7 +9,9 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + "sigs.k8s.io/cluster-api/controllers/external" "sigs.k8s.io/cluster-api/controllers/remote" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -64,30 +66,62 @@ func CopySecretToRemoteCluster( return nil } -// EnsureOwnerReferenceForSecret will ensure that the secretName Secret has an OwnerReference of the cluster. -func EnsureOwnerReferenceForSecret( +// EnsureClusterOwnerReferenceForObject ensures that OwnerReference of the cluster is added on provided object. +func EnsureClusterOwnerReferenceForObject( ctx context.Context, cl ctrlclient.Client, - secretName string, + objectRef corev1.TypedLocalObjectReference, cluster *clusterv1.Cluster, ) error { - secret, err := getSecretForCluster(ctx, cl, secretName, cluster) + targetObj, err := GetResourceFromTypedLocalObjectReference( + ctx, + cl, + objectRef, + cluster.Namespace, + ) if err != nil { return err } - err = controllerutil.SetOwnerReference(cluster, secret, cl.Scheme()) + err = controllerutil.SetOwnerReference(cluster, targetObj, cl.Scheme()) if err != nil { - return fmt.Errorf("failed to set owner reference on Secret: %w", err) + return fmt.Errorf("failed to set cluster's owner reference on object: %w", err) } - err = cl.Update(ctx, secret) + err = cl.Update(ctx, targetObj) if err != nil { - return fmt.Errorf("failed to update Secret with owner references: %w", err) + return fmt.Errorf("failed to update object with cluster's owner reference: %w", err) } return nil } +// GetResourceFromTypedLocalObjectReference gets the resource from the provided TypedLocalObjectReference. +func GetResourceFromTypedLocalObjectReference( + ctx context.Context, + cl ctrlclient.Client, + typedLocalObjectRef corev1.TypedLocalObjectReference, + ns string, +) (*unstructured.Unstructured, error) { + apiVersion := corev1.SchemeGroupVersion.String() + if typedLocalObjectRef.APIGroup != nil { + apiVersion = *typedLocalObjectRef.APIGroup + } + + objectRef := &corev1.ObjectReference{ + APIVersion: apiVersion, + Kind: typedLocalObjectRef.Kind, + Name: typedLocalObjectRef.Name, + Namespace: ns, + } + + targetObj, err := external.Get(ctx, cl, objectRef) + if err != nil { + return nil, fmt.Errorf("failed to get resource from object reference: %w", err) + } + + return targetObj, nil +} + func getSecretForCluster( ctx context.Context, c ctrlclient.Client, diff --git a/pkg/handlers/utils/secrets_test.go b/pkg/handlers/utils/secrets_test.go index 770bac7db..cf8f8c496 100644 --- a/pkg/handlers/utils/secrets_test.go +++ b/pkg/handlers/utils/secrets_test.go @@ -5,12 +5,14 @@ package utils import ( "context" + "fmt" "testing" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" + apiErrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -97,23 +99,38 @@ func Test_EnsureOwnerReferenceForSecret(t *testing.T) { client: buildFakeClient(t, testSecret, testCluster), secretName: "missing-secret", cluster: testCluster, - wantErr: errors.NewNotFound(corev1.Resource("secrets"), "missing-secret"), + wantErr: fmt.Errorf( + "failed to get resource from object reference: %w", + errors.Wrapf( + apiErrors.NewNotFound(corev1.Resource("secrets"), "missing-secret"), + "failed to retrieve %s %s", + "Secret", + "missing-secret", + ), + ), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() - err := EnsureOwnerReferenceForSecret( + err := EnsureClusterOwnerReferenceForObject( context.Background(), tt.client, - tt.secretName, + corev1.TypedLocalObjectReference{ + Kind: "Secret", + Name: tt.secretName, + }, tt.cluster, ) - require.Equal(t, tt.wantErr, err) + if tt.wantErr != nil { + assert.Equal(t, tt.wantErr.Error(), err.Error()) return + } else { + require.NoError(t, err) } + // verify that the owner reference was added secret := &corev1.Secret{} err = tt.client.Get(