diff --git a/changelogs/unreleased/8487-Lyndon-Li b/changelogs/unreleased/8487-Lyndon-Li new file mode 100644 index 0000000000..cd67ee404d --- /dev/null +++ b/changelogs/unreleased/8487-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #8433, add third party labels to data mover pods when the same labels exist in node-agent pods \ No newline at end of file diff --git a/pkg/controller/data_download_controller.go b/pkg/controller/data_download_controller.go index 39973fbc5f..bc7d7c6e78 100644 --- a/pkg/controller/data_download_controller.go +++ b/pkg/controller/data_download_controller.go @@ -47,7 +47,9 @@ import ( "github.com/vmware-tanzu/velero/pkg/datapath" "github.com/vmware-tanzu/velero/pkg/exposer" "github.com/vmware-tanzu/velero/pkg/metrics" + "github.com/vmware-tanzu/velero/pkg/nodeagent" "github.com/vmware-tanzu/velero/pkg/uploader" + "github.com/vmware-tanzu/velero/pkg/util" "github.com/vmware-tanzu/velero/pkg/util/kube" ) @@ -178,6 +180,15 @@ func (r *DataDownloadReconciler) Reconcile(ctx context.Context, req ctrl.Request } hostingPodLabels := map[string]string{velerov1api.DataDownloadLabel: dd.Name} + for _, k := range util.ThirdPartyLabels { + if v, err := nodeagent.GetLabelValue(ctx, r.kubeClient, dd.Namespace, k); err != nil { + if err != nodeagent.ErrNodeAgentLabelNotFound { + log.WithError(err).Warnf("Failed to check node-agent label, skip adding host pod label %s", k) + } + } else { + hostingPodLabels[k] = v + } + } // Expose() will trigger to create one pod whose volume is restored by a given volume snapshot, // but the pod maybe is not in the same node of the current controller, so we need to return it here. diff --git a/pkg/controller/data_upload_controller.go b/pkg/controller/data_upload_controller.go index ecf23ced8e..50fac180a1 100644 --- a/pkg/controller/data_upload_controller.go +++ b/pkg/controller/data_upload_controller.go @@ -50,6 +50,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/metrics" "github.com/vmware-tanzu/velero/pkg/nodeagent" "github.com/vmware-tanzu/velero/pkg/uploader" + "github.com/vmware-tanzu/velero/pkg/util" "github.com/vmware-tanzu/velero/pkg/util/kube" ) @@ -810,11 +811,22 @@ func (r *DataUploadReconciler) setupExposeParam(du *velerov2alpha1api.DataUpload accessMode = exposer.AccessModeBlock } + hostingPodLabels := map[string]string{velerov1api.DataUploadLabel: du.Name} + for _, k := range util.ThirdPartyLabels { + if v, err := nodeagent.GetLabelValue(context.Background(), r.kubeClient, du.Namespace, k); err != nil { + if err != nodeagent.ErrNodeAgentLabelNotFound { + r.logger.WithError(err).Warnf("Failed to check node-agent label, skip adding host pod label %s", k) + } + } else { + hostingPodLabels[k] = v + } + } + return &exposer.CSISnapshotExposeParam{ SnapshotName: du.Spec.CSISnapshot.VolumeSnapshot, SourceNamespace: du.Spec.SourceNamespace, StorageClass: du.Spec.CSISnapshot.StorageClass, - HostingPodLabels: map[string]string{velerov1api.DataUploadLabel: du.Name}, + HostingPodLabels: hostingPodLabels, AccessMode: accessMode, OperationTimeout: du.Spec.OperationTimeout.Duration, ExposeTimeout: r.preparingTimeout, diff --git a/pkg/nodeagent/node_agent.go b/pkg/nodeagent/node_agent.go index b83efc6f47..ff5d011eca 100644 --- a/pkg/nodeagent/node_agent.go +++ b/pkg/nodeagent/node_agent.go @@ -38,7 +38,8 @@ const ( ) var ( - ErrDaemonSetNotFound = errors.New("daemonset not found") + ErrDaemonSetNotFound = errors.New("daemonset not found") + ErrNodeAgentLabelNotFound = errors.New("node-agent label not found") ) type LoadConcurrency struct { @@ -161,3 +162,21 @@ func GetConfigs(ctx context.Context, namespace string, kubeClient kubernetes.Int return configs, nil } + +func GetLabelValue(ctx context.Context, kubeClient kubernetes.Interface, namespace string, key string) (string, error) { + ds, err := kubeClient.AppsV1().DaemonSets(namespace).Get(ctx, daemonSet, metav1.GetOptions{}) + if err != nil { + return "", errors.Wrap(err, "error getting node-agent daemonset") + } + + if ds.Spec.Template.Labels == nil { + return "", ErrNodeAgentLabelNotFound + } + + val, found := ds.Spec.Template.Labels[key] + if !found { + return "", ErrNodeAgentLabelNotFound + } + + return val, nil +} diff --git a/pkg/nodeagent/node_agent_test.go b/pkg/nodeagent/node_agent_test.go index 9bbf0f46d1..1c24427b1f 100644 --- a/pkg/nodeagent/node_agent_test.go +++ b/pkg/nodeagent/node_agent_test.go @@ -331,3 +331,132 @@ func TestGetConfigs(t *testing.T) { }) } } + +func TestGetLabelValue(t *testing.T) { + daemonSet := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-ns", + Name: "node-agent", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "DaemonSet", + }, + } + + daemonSetWithOtherLabel := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-ns", + Name: "node-agent", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "DaemonSet", + }, + Spec: appsv1.DaemonSetSpec{ + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "fake-other-label": "fake-value-1", + }, + }, + }, + }, + } + + daemonSetWithLabel := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-ns", + Name: "node-agent", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "DaemonSet", + }, + Spec: appsv1.DaemonSetSpec{ + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "fake-label": "fake-value-2", + }, + }, + }, + }, + } + + daemonSetWithEmptyLabel := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-ns", + Name: "node-agent", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "DaemonSet", + }, + Spec: appsv1.DaemonSetSpec{ + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "fake-label": "", + }, + }, + }, + }, + } + + tests := []struct { + name string + kubeClientObj []runtime.Object + namespace string + expectedValue string + expectErr string + }{ + { + name: "ds get error", + namespace: "fake-ns", + expectErr: "error getting node-agent daemonset: daemonsets.apps \"node-agent\" not found", + }, + { + name: "no label", + namespace: "fake-ns", + kubeClientObj: []runtime.Object{ + daemonSet, + }, + expectErr: ErrNodeAgentLabelNotFound.Error(), + }, + { + name: "no expecting label", + namespace: "fake-ns", + kubeClientObj: []runtime.Object{ + daemonSetWithOtherLabel, + }, + expectErr: ErrNodeAgentLabelNotFound.Error(), + }, + { + name: "expecting label", + namespace: "fake-ns", + kubeClientObj: []runtime.Object{ + daemonSetWithLabel, + }, + expectedValue: "fake-value-2", + }, + { + name: "expecting empty label", + namespace: "fake-ns", + kubeClientObj: []runtime.Object{ + daemonSetWithEmptyLabel, + }, + expectedValue: "", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fakeKubeClient := fake.NewSimpleClientset(test.kubeClientObj...) + + value, err := GetLabelValue(context.TODO(), fakeKubeClient, test.namespace, "fake-label") + if test.expectErr == "" { + assert.NoError(t, err) + assert.Equal(t, test.expectedValue, value) + } else { + assert.EqualError(t, err, test.expectErr) + } + }) + } +} diff --git a/pkg/util/third_party.go b/pkg/util/third_party.go new file mode 100644 index 0000000000..2be1586811 --- /dev/null +++ b/pkg/util/third_party.go @@ -0,0 +1,21 @@ +/* +Copyright the Velero contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +var ThirdPartyLabels []string = []string{ + "azure.workload.identity/use", +}