Repository: kubernetes-sigs/cluster-api-provider-kubevirt (go)
Issue: CAPK node's userdata secrets are missing label
**What steps did you take and what happened:**

When creating a new cluster, the userdata secrets created by CAPK to extend Kubeadm secrets with the `capk` user, have no label.

**What did you expect to happen:**

The secret should inherit the labels from the secrets generated by Kubeadm.


**Environment:**

- Cluster-api version: **v1beta1**
- Cluster-api-provider-kubevirt version: **v1alpha1**
- Kubernetes version: (use `kubectl version`): **v1.20.15**
- KubeVirt version: **v1**
- OS (e.g. from `/etc/os-release`): **CentOS 7**

/kind bug

Pull request description: Copy Kubeadm userdata secret labels to CAPK secret.
**What this PR does / why we need it**:

This ensures that the `...-userdata` secret CAPK creates to enhance the cloud-init user data generated by Kubeadm has the same label(s) that the latter.

Currently, this results in these secrets getting the `cluster.x-k8s.io/cluster-name=<cluster-name>` label.

**Which issue this PR fixes**: 

fixes #161

**Release notes**:

```release-note
NONE
```


Patch:
diff --git a/controllers/kubevirtmachine_controller.go b/controllers/kubevirtmachine_controller.go
index b51c7b6..a724d3d 100644
--- a/controllers/kubevirtmachine_controller.go
+++ b/controllers/kubevirtmachine_controller.go
@@ -596,6 +596,7 @@ func (r *KubevirtMachineReconciler) reconcileKubevirtBootstrapSecret(ctx *contex
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      s.Name + "-userdata",
 			Namespace: vmNamespace,
+			Labels:    s.Labels,
 		},
 	}
 	ctx.BootstrapDataSecret = newBootstrapDataSecret


Test patch:
diff --git a/controllers/kubevirtmachine_controller_test.go b/controllers/kubevirtmachine_controller_test.go
index bdbe3a3..9039597 100644
--- a/controllers/kubevirtmachine_controller_test.go
+++ b/controllers/kubevirtmachine_controller_test.go
@@ -25,13 +25,13 @@ import (
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
 
-	"sigs.k8s.io/cluster-api-provider-kubevirt/pkg/kubevirt"
-
 	corev1 "k8s.io/api/core/v1"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
 	kubevirtv1 "kubevirt.io/api/core/v1"
+	"sigs.k8s.io/cluster-api-provider-kubevirt/pkg/kubevirt"
 
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/util/conditions"
@@ -189,7 +189,8 @@ var _ = Describe("reconcile a kubevirt machine", func() {
 
 		sshKeySecret = &corev1.Secret{
 			ObjectMeta: metav1.ObjectMeta{
-				Name: sshKeySecretName,
+				Name:   sshKeySecretName,
+				Labels: map[string]string{"hello": "world"},
 			},
 			Data: map[string][]byte{
 				"pub": []byte("sha-rsa 1234"),
@@ -199,7 +200,8 @@ var _ = Describe("reconcile a kubevirt machine", func() {
 
 		bootstrapSecret = &corev1.Secret{
 			ObjectMeta: metav1.ObjectMeta{
-				Name: bootstrapSecretName,
+				Name:   bootstrapSecretName,
+				Labels: map[string]string{"hello": "world"},
 			},
 			Data: map[string][]byte{
 				"value": []byte("shell-script"),
@@ -266,7 +268,6 @@ var _ = Describe("reconcile a kubevirt machine", func() {
 			kubevirtMachine,
 			sshKeySecret,
 			bootstrapSecret,
-			bootstrapUserDataSecret,
 		}
 
 		setupClient(kubevirt.DefaultMachineFactory{}, objects)
@@ -289,6 +290,16 @@ var _ = Describe("reconcile a kubevirt machine", func() {
 		// Should expect kubevirt machine is still not ready
 		Expect(machineContext.KubevirtMachine.Status.Ready).To(BeFalse())
 		Expect(machineContext.KubevirtMachine.Spec.ProviderID).To(BeNil())
+
+		// Should have created the userdata secret
+		machineBootstrapSecretReferenceName := machineContext.Machine.Spec.Bootstrap.DataSecretName
+		machineBootstrapSecretReferenceKey := client.ObjectKey{Namespace: machineContext.Machine.GetNamespace(), Name: *machineBootstrapSecretReferenceName + "-userdata"}
+		bootstrapDataSecret := &corev1.Secret{}
+		err = fakeClient.Get(gocontext.Background(), machineBootstrapSecretReferenceKey, bootstrapDataSecret)
+		Expect(err).NotTo(HaveOccurred())
+		Expect(bootstrapDataSecret.Data).To(HaveKeyWithValue("userdata", []byte("shell-script")))
+		Expect(bootstrapDataSecret.Labels).To(HaveLen(1))
+		Expect(bootstrapDataSecret.Labels).To(HaveKeyWithValue("hello", "world"))
 	})
 
 	It("should ensure deletion of KubevirtMachine garbage collects everything successfully", func() {
@@ -332,8 +343,7 @@ var _ = Describe("reconcile a kubevirt machine", func() {
 		Expect(err).NotTo(HaveOccurred())
 		bootstrapDataSecret := &corev1.Secret{}
 		err = infraClusterClient.Get(gocontext.Background(), machineBootstrapSecretReferenceKey, bootstrapDataSecret)
-		expectedErrorMessage := "secrets \"" + *machineBootstrapSecretReferenceName + "-userdata" + "\" not found"
-		Expect(err.Error()).To(Equal(expectedErrorMessage))
+		Expect(apierrors.IsNotFound(err)).To(BeTrue())
 
 		//Check finalizer is removed from machine
 		Expect(len(machineContext.Machine.ObjectMeta.Finalizers)).To(Equal(0))
@@ -449,7 +459,6 @@ var _ = Describe("reconcile a kubevirt machine", func() {
 			machine,
 			kubevirtMachine,
 			bootstrapSecret,
-			bootstrapUserDataSecret,
 		}
 
 		setupClient(kubevirt.DefaultMachineFactory{}, objects)
@@ -472,6 +481,16 @@ var _ = Describe("reconcile a kubevirt machine", func() {
 		// Should expect kubevirt machine is still not ready
 		Expect(machineContext.KubevirtMachine.Status.Ready).To(BeFalse())
 		Expect(machineContext.KubevirtMachine.Spec.ProviderID).To(BeNil())
+
+		// Should have created the userdata secret
+		machineBootstrapSecretReferenceName := machineContext.Machine.Spec.Bootstrap.DataSecretName
+		machineBootstrapSecretReferenceKey := client.ObjectKey{Namespace: kubevirtMachine.Namespace, Name: *machineBootstrapSecretReferenceName + "-userdata"}
+		bootstrapDataSecret := &corev1.Secret{}
+		err = fakeClient.Get(gocontext.Background(), machineBootstrapSecretReferenceKey, bootstrapDataSecret)
+		Expect(err).NotTo(HaveOccurred())
+		Expect(bootstrapDataSecret.Data).To(HaveKeyWithValue("userdata", []byte("shell-script")))
+		Expect(bootstrapDataSecret.Labels).To(HaveLen(1))
+		Expect(bootstrapDataSecret.Labels).To(HaveKeyWithValue("hello", "world"))
 	})
 
 	It("should create KubeVirt VM in custom namespace", func() {
@@ -486,7 +505,6 @@ var _ = Describe("reconcile a kubevirt machine", func() {
 			kubevirtMachine,
 			sshKeySecret,
 			bootstrapSecret,
-			bootstrapUserDataSecret,
 		}
 
 		setupClient(kubevirt.DefaultMachineFactory{}, objects)
@@ -509,6 +527,16 @@ var _ = Describe("reconcile a kubevirt machine", func() {
 		// Should expect kubevirt machine is still not ready
 		Expect(machineContext.KubevirtMachine.Status.Ready).To(BeFalse())
 		Expect(machineContext.KubevirtMachine.Spec.ProviderID).To(BeNil())
+
+		// Should have created the userdata secret
+		machineBootstrapSecretReferenceName := machineContext.Machine.Spec.Bootstrap.DataSecretName
+		machineBootstrapSecretReferenceKey := client.ObjectKey{Namespace: customNamespace, Name: *machineBootstrapSecretReferenceName + "-userdata"}
+		bootstrapDataSecret := &corev1.Secret{}
+		err = fakeClient.Get(gocontext.Background(), machineBootstrapSecretReferenceKey, bootstrapDataSecret)
+		Expect(err).NotTo(HaveOccurred())
+		Expect(bootstrapDataSecret.Data).To(HaveKeyWithValue("userdata", []byte("shell-script")))
+		Expect(bootstrapDataSecret.Labels).To(HaveLen(1))
+		Expect(bootstrapDataSecret.Labels).To(HaveKeyWithValue("hello", "world"))
 	})
 
 	It("should detect when VMI is ready and mark KubevirtMachine ready", func() {