From 924f4056f9e47017738beb195597c9d5f1643aa8 Mon Sep 17 00:00:00 2001 From: Fabian Kramm Date: Tue, 20 Aug 2024 11:52:08 +0200 Subject: [PATCH 1/4] refactor: add host name & namespace as annotations --- pkg/controllers/generic/import_syncer.go | 2 + .../resources/configmaps/syncer_test.go | 10 +- .../csistoragecapacities/syncer_test.go | 20 ++- .../csistoragecapacities/translate.go | 2 +- .../resources/endpoints/syncer_test.go | 30 ++-- .../resources/ingresses/syncer_test.go | 14 +- .../resources/networkpolicies/syncer_test.go | 10 +- .../persistentvolumeclaims/syncer_test.go | 28 ++-- .../poddisruptionbudgets/syncer_test.go | 10 +- pkg/controllers/resources/pods/syncer_test.go | 6 + .../resources/secrets/syncer_test.go | 10 +- .../resources/serviceaccounts/syncer_test.go | 2 + .../resources/services/syncer_test.go | 12 +- .../resources/storageclasses/syncer_test.go | 14 +- .../volumesnapshotcontents/syncer_test.go | 7 +- .../volumesnapshots/syncer_test.go | 10 +- pkg/mappings/generic/mapper.go | 60 ++++++-- pkg/mappings/generic/mapper_test.go | 138 +++++++++++++++++- pkg/syncer/syncer_test.go | 32 ++-- pkg/util/translate/multi_namespace.go | 7 + pkg/util/translate/single_namespace.go | 7 + pkg/util/translate/translate.go | 12 +- pkg/util/translate/translate_test.go | 2 + pkg/util/translate/types.go | 10 +- 24 files changed, 347 insertions(+), 108 deletions(-) diff --git a/pkg/controllers/generic/import_syncer.go b/pkg/controllers/generic/import_syncer.go index d4323579d0..9914ff7340 100644 --- a/pkg/controllers/generic/import_syncer.go +++ b/pkg/controllers/generic/import_syncer.go @@ -426,6 +426,8 @@ func (s *importer) updateVirtualAnnotations(a map[string]string) map[string]stri delete(a, translate.NamespaceAnnotation) delete(a, translate.UIDAnnotation) delete(a, translate.KindAnnotation) + delete(a, translate.HostNameAnnotation) + delete(a, translate.HostNamespaceAnnotation) delete(a, corev1.LastAppliedConfigAnnotation) return a } diff --git a/pkg/controllers/resources/configmaps/syncer_test.go b/pkg/controllers/resources/configmaps/syncer_test.go index c04f8f728f..839c27c08e 100644 --- a/pkg/controllers/resources/configmaps/syncer_test.go +++ b/pkg/controllers/resources/configmaps/syncer_test.go @@ -31,10 +31,12 @@ func TestSync(t *testing.T) { Name: translate.Default.HostName(nil, baseConfigMap.Name, baseConfigMap.Namespace).Name, Namespace: "test", Annotations: map[string]string{ - translate.NameAnnotation: baseConfigMap.Name, - translate.NamespaceAnnotation: baseConfigMap.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("ConfigMap").String(), + translate.NameAnnotation: baseConfigMap.Name, + translate.NamespaceAnnotation: baseConfigMap.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("ConfigMap").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, baseConfigMap.Name, baseConfigMap.Namespace).Name, }, Labels: map[string]string{ translate.NamespaceLabel: baseConfigMap.Namespace, diff --git a/pkg/controllers/resources/csistoragecapacities/syncer_test.go b/pkg/controllers/resources/csistoragecapacities/syncer_test.go index b88c5e1b29..ee59c6a05c 100644 --- a/pkg/controllers/resources/csistoragecapacities/syncer_test.go +++ b/pkg/controllers/resources/csistoragecapacities/syncer_test.go @@ -32,10 +32,12 @@ func TestSyncHostStorageClass(t *testing.T) { Name: "test-csistoragecapacity-x-test", Namespace: "kube-system", Annotations: map[string]string{ - translate.NameAnnotation: "test-csistoragecapacity", - translate.NamespaceAnnotation: "test", - translate.UIDAnnotation: "", - translate.KindAnnotation: storagev1.SchemeGroupVersion.WithKind("CSIStorageCapacity").String(), + translate.NameAnnotation: "test-csistoragecapacity", + translate.NamespaceAnnotation: "test", + translate.UIDAnnotation: "", + translate.KindAnnotation: storagev1.SchemeGroupVersion.WithKind("CSIStorageCapacity").String(), + translate.HostNameAnnotation: "test-csistoragecapacity-x-test", + translate.HostNamespaceAnnotation: "kube-system", }, Labels: map[string]string{ "vcluster.loft.sh/namespace": "test", @@ -159,10 +161,12 @@ func TestSyncStorageClass(t *testing.T) { Name: "test-csistoragecapacity-x-test", Namespace: "kube-system", Annotations: map[string]string{ - translate.NameAnnotation: "test-csistoragecapacity", - translate.NamespaceAnnotation: "test", - translate.UIDAnnotation: "", - translate.KindAnnotation: storagev1.SchemeGroupVersion.WithKind("CSIStorageCapacity").String(), + translate.NameAnnotation: "test-csistoragecapacity", + translate.NamespaceAnnotation: "test", + translate.UIDAnnotation: "", + translate.KindAnnotation: storagev1.SchemeGroupVersion.WithKind("CSIStorageCapacity").String(), + translate.HostNameAnnotation: "test-csistoragecapacity-x-test", + translate.HostNamespaceAnnotation: "kube-system", }, Labels: map[string]string{ "vcluster.loft.sh/namespace": "test", diff --git a/pkg/controllers/resources/csistoragecapacities/translate.go b/pkg/controllers/resources/csistoragecapacities/translate.go index efc83725fc..1befa565e2 100644 --- a/pkg/controllers/resources/csistoragecapacities/translate.go +++ b/pkg/controllers/resources/csistoragecapacities/translate.go @@ -62,7 +62,7 @@ func (s *csistoragecapacitySyncer) translateBackwards(ctx *synccontext.SyncConte // TranslateMetadata translates the object's metadata func (s *csistoragecapacitySyncer) virtualMetadata(ctx *synccontext.SyncContext, pObj *storagev1.CSIStorageCapacity) *storagev1.CSIStorageCapacity { vObj := translate.CopyObjectWithName(pObj, s.HostToVirtual(ctx, types.NamespacedName{Name: pObj.Name, Namespace: pObj.Namespace}, pObj), false) - vObj.SetAnnotations(translate.HostAnnotations(pObj, nil)) + vObj.SetAnnotations(translate.HostAnnotations(pObj, vObj)) vObj.SetLabels(translate.HostLabels(pObj, nil)) return vObj } diff --git a/pkg/controllers/resources/endpoints/syncer_test.go b/pkg/controllers/resources/endpoints/syncer_test.go index 26d860acd0..1025e001a6 100644 --- a/pkg/controllers/resources/endpoints/syncer_test.go +++ b/pkg/controllers/resources/endpoints/syncer_test.go @@ -57,10 +57,12 @@ func TestExistingEndpoints(t *testing.T) { Name: translate.Default.HostName(nil, vEndpoints.Name, vEndpoints.Namespace).Name, Namespace: "test", Annotations: map[string]string{ - translate.NameAnnotation: vEndpoints.Name, - translate.NamespaceAnnotation: vEndpoints.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Service").String(), + translate.NameAnnotation: vEndpoints.Name, + translate.NamespaceAnnotation: vEndpoints.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Service").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, vEndpoints.Name, vEndpoints.Namespace).Name, }, Labels: map[string]string{ translate.NamespaceLabel: vEndpoints.Namespace, @@ -72,10 +74,12 @@ func TestExistingEndpoints(t *testing.T) { Name: translate.Default.HostName(nil, vEndpoints.Name, vEndpoints.Namespace).Name, Namespace: "test", Annotations: map[string]string{ - translate.NameAnnotation: vEndpoints.Name, - translate.NamespaceAnnotation: vEndpoints.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Endpoints").String(), + translate.NameAnnotation: vEndpoints.Name, + translate.NamespaceAnnotation: vEndpoints.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Endpoints").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, vEndpoints.Name, vEndpoints.Namespace).Name, }, Labels: map[string]string{ translate.NamespaceLabel: vEndpoints.Namespace, @@ -151,10 +155,12 @@ func TestSync(t *testing.T) { Name: translate.Default.HostName(nil, baseEndpoints.Name, baseEndpoints.Namespace).Name, Namespace: "test", Annotations: map[string]string{ - translate.NameAnnotation: baseEndpoints.Name, - translate.NamespaceAnnotation: baseEndpoints.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Endpoints").String(), + translate.NameAnnotation: baseEndpoints.Name, + translate.NamespaceAnnotation: baseEndpoints.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Endpoints").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, baseEndpoints.Name, baseEndpoints.Namespace).Name, }, Labels: map[string]string{ translate.NamespaceLabel: baseEndpoints.Namespace, diff --git a/pkg/controllers/resources/ingresses/syncer_test.go b/pkg/controllers/resources/ingresses/syncer_test.go index 89ef746081..755a323291 100644 --- a/pkg/controllers/resources/ingresses/syncer_test.go +++ b/pkg/controllers/resources/ingresses/syncer_test.go @@ -108,10 +108,12 @@ func TestSync(t *testing.T) { Name: translate.Default.HostName(nil, "testingress", "test").Name, Namespace: "test", Annotations: map[string]string{ - translate.NameAnnotation: vObjectMeta.Name, - translate.NamespaceAnnotation: vObjectMeta.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: networkingv1.SchemeGroupVersion.WithKind("Ingress").String(), + translate.NameAnnotation: vObjectMeta.Name, + translate.NamespaceAnnotation: vObjectMeta.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: networkingv1.SchemeGroupVersion.WithKind("Ingress").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, "testingress", "test").Name, }, Labels: map[string]string{ translate.MarkerLabel: translate.VClusterName, @@ -345,6 +347,8 @@ func TestSync(t *testing.T) { "vcluster.loft.sh/object-namespace": baseIngress.Namespace, translate.UIDAnnotation: "", translate.KindAnnotation: networkingv1.SchemeGroupVersion.WithKind("Ingress").String(), + translate.HostNamespaceAnnotation: createdIngress.Namespace, + translate.HostNameAnnotation: createdIngress.Name, }, }, }, @@ -420,6 +424,8 @@ func TestSync(t *testing.T) { "vcluster.loft.sh/object-namespace": baseIngress.Namespace, translate.UIDAnnotation: "", translate.KindAnnotation: networkingv1.SchemeGroupVersion.WithKind("Ingress").String(), + translate.HostNamespaceAnnotation: createdIngress.Namespace, + translate.HostNameAnnotation: createdIngress.Name, "alb.ingress.kubernetes.io/actions.testservice-x-test-x-suffix": `{"forwardConfig":{"targetGroups":[{"serviceName":"nginx-service-x-test-x-suffix","servicePort":"80","weight":100}]}}`, "alb.ingress.kubernetes.io/actions.ssl-redirect-x-test-x-suffix": `{"redirectConfig":{"Port":"443","Protocol":"HTTPS","StatusCode":"HTTP_301"},"type":"redirect","forwardConfig":{}}`, }, diff --git a/pkg/controllers/resources/networkpolicies/syncer_test.go b/pkg/controllers/resources/networkpolicies/syncer_test.go index aa5356b492..40094a6251 100644 --- a/pkg/controllers/resources/networkpolicies/syncer_test.go +++ b/pkg/controllers/resources/networkpolicies/syncer_test.go @@ -66,10 +66,12 @@ func TestSync(t *testing.T) { Name: translate.Default.HostName(nil, "testnetworkpolicy", "test").Name, Namespace: "test", Annotations: map[string]string{ - translate.NameAnnotation: vObjectMeta.Name, - translate.NamespaceAnnotation: vObjectMeta.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: networkingv1.SchemeGroupVersion.WithKind("NetworkPolicy").String(), + translate.NameAnnotation: vObjectMeta.Name, + translate.NamespaceAnnotation: vObjectMeta.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: networkingv1.SchemeGroupVersion.WithKind("NetworkPolicy").String(), + translate.HostNameAnnotation: translate.Default.HostName(nil, "testnetworkpolicy", "test").Name, + translate.HostNamespaceAnnotation: "test", }, Labels: map[string]string{ translate.MarkerLabel: translate.VClusterName, diff --git a/pkg/controllers/resources/persistentvolumeclaims/syncer_test.go b/pkg/controllers/resources/persistentvolumeclaims/syncer_test.go index 93e42fa876..bbed7bc9cd 100644 --- a/pkg/controllers/resources/persistentvolumeclaims/syncer_test.go +++ b/pkg/controllers/resources/persistentvolumeclaims/syncer_test.go @@ -29,10 +29,12 @@ func TestSync(t *testing.T) { Name: translate.Default.HostName(nil, "testpvc", "testns").Name, Namespace: "test", Annotations: map[string]string{ - translate.NameAnnotation: vObjectMeta.Name, - translate.NamespaceAnnotation: vObjectMeta.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("PersistentVolumeClaim").String(), + translate.NameAnnotation: vObjectMeta.Name, + translate.NamespaceAnnotation: vObjectMeta.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("PersistentVolumeClaim").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, "testpvc", "testns").Name, }, Labels: map[string]string{ translate.MarkerLabel: translate.VClusterName, @@ -81,6 +83,8 @@ func TestSync(t *testing.T) { translate.NamespaceAnnotation: vObjectMeta.Namespace, translate.UIDAnnotation: "", translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("PersistentVolumeClaim").String(), + translate.HostNamespaceAnnotation: pObjectMeta.Namespace, + translate.HostNameAnnotation: pObjectMeta.Name, translate.ManagedAnnotationsAnnotation: "otherAnnotationKey", "otherAnnotationKey": "update this", }, @@ -95,13 +99,15 @@ func TestSync(t *testing.T) { Name: pObjectMeta.Name, Namespace: pObjectMeta.Namespace, Annotations: map[string]string{ - translate.NameAnnotation: vObjectMeta.Name, - translate.NamespaceAnnotation: vObjectMeta.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("PersistentVolumeClaim").String(), - bindCompletedAnnotation: "testannotation", - boundByControllerAnnotation: "testannotation2", - storageProvisionerAnnotation: "testannotation3", + translate.NameAnnotation: vObjectMeta.Name, + translate.NamespaceAnnotation: vObjectMeta.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("PersistentVolumeClaim").String(), + translate.HostNameAnnotation: pObjectMeta.Name, + translate.HostNamespaceAnnotation: pObjectMeta.Namespace, + bindCompletedAnnotation: "testannotation", + boundByControllerAnnotation: "testannotation2", + storageProvisionerAnnotation: "testannotation3", }, Labels: pObjectMeta.Labels, }, diff --git a/pkg/controllers/resources/poddisruptionbudgets/syncer_test.go b/pkg/controllers/resources/poddisruptionbudgets/syncer_test.go index 05294184f9..35b94ea76c 100644 --- a/pkg/controllers/resources/poddisruptionbudgets/syncer_test.go +++ b/pkg/controllers/resources/poddisruptionbudgets/syncer_test.go @@ -28,10 +28,12 @@ func TestSync(t *testing.T) { Name: translate.Default.HostName(nil, "testPDB", vObjectMeta.Namespace).Name, Namespace: "test", Annotations: map[string]string{ - translate.NameAnnotation: vObjectMeta.Name, - translate.NamespaceAnnotation: vObjectMeta.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: policyv1.SchemeGroupVersion.WithKind("PodDisruptionBudget").String(), + translate.NameAnnotation: vObjectMeta.Name, + translate.NamespaceAnnotation: vObjectMeta.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: policyv1.SchemeGroupVersion.WithKind("PodDisruptionBudget").String(), + translate.HostNameAnnotation: translate.Default.HostName(nil, "testPDB", vObjectMeta.Namespace).Name, + translate.HostNamespaceAnnotation: "test", }, Labels: map[string]string{ translate.NamespaceLabel: vObjectMeta.Namespace, diff --git a/pkg/controllers/resources/pods/syncer_test.go b/pkg/controllers/resources/pods/syncer_test.go index e02c610952..5e990448c6 100644 --- a/pkg/controllers/resources/pods/syncer_test.go +++ b/pkg/controllers/resources/pods/syncer_test.go @@ -66,6 +66,8 @@ func TestSyncTable(t *testing.T) { translate.UIDAnnotation: "", translate.NamespaceAnnotation: vObjectMeta.Namespace, translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Pod").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, "testpod", "testns").Name, podtranslate.ServiceAccountNameAnnotation: "", podtranslate.UIDAnnotation: string(vObjectMeta.UID), }, @@ -365,6 +367,8 @@ func TestSync(t *testing.T) { translate.UIDAnnotation: "", translate.NamespaceAnnotation: vObjectMeta.Namespace, translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Pod").String(), + translate.HostNameAnnotation: translate.Default.HostName(nil, "testpod", "testns").Name, + translate.HostNamespaceAnnotation: "test", podtranslate.ServiceAccountNameAnnotation: "", podtranslate.UIDAnnotation: string(vObjectMeta.UID), }, @@ -467,6 +471,8 @@ func TestSync(t *testing.T) { translate.NamespaceAnnotation: vHostPathPod.Namespace, translate.UIDAnnotation: "", translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Pod").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, vHostPathPod.Name, testingutil.DefaultTestCurrentNamespace).Name, podtranslate.ServiceAccountNameAnnotation: "", podtranslate.UIDAnnotation: string(vHostPathPod.UID), }, diff --git a/pkg/controllers/resources/secrets/syncer_test.go b/pkg/controllers/resources/secrets/syncer_test.go index f304d32d6e..e73f2629e6 100644 --- a/pkg/controllers/resources/secrets/syncer_test.go +++ b/pkg/controllers/resources/secrets/syncer_test.go @@ -43,10 +43,12 @@ func TestSync(t *testing.T) { Name: translate.Default.HostName(nil, baseSecret.Name, baseSecret.Namespace).Name, Namespace: "test", Annotations: map[string]string{ - translate.NameAnnotation: baseSecret.Name, - translate.NamespaceAnnotation: baseSecret.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.NameAnnotation: baseSecret.Name, + translate.NamespaceAnnotation: baseSecret.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, baseSecret.Name, baseSecret.Namespace).Name, }, Labels: map[string]string{ translate.NamespaceLabel: baseSecret.Namespace, diff --git a/pkg/controllers/resources/serviceaccounts/syncer_test.go b/pkg/controllers/resources/serviceaccounts/syncer_test.go index ba73fa40a4..b38a17a2c6 100644 --- a/pkg/controllers/resources/serviceaccounts/syncer_test.go +++ b/pkg/controllers/resources/serviceaccounts/syncer_test.go @@ -46,6 +46,8 @@ func TestSync(t *testing.T) { translate.NamespaceAnnotation: vSA.Namespace, translate.UIDAnnotation: "", translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("ServiceAccount").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, vSA.Name, vSA.Namespace).Name, }, Labels: map[string]string{ translate.NamespaceLabel: vSA.Namespace, diff --git a/pkg/controllers/resources/services/syncer_test.go b/pkg/controllers/resources/services/syncer_test.go index 5216c425ff..5c7f8fbd20 100644 --- a/pkg/controllers/resources/services/syncer_test.go +++ b/pkg/controllers/resources/services/syncer_test.go @@ -28,10 +28,12 @@ func TestSync(t *testing.T) { Name: translate.Default.HostName(nil, "testservice", "testns").Name, Namespace: "test", Annotations: map[string]string{ - translate.NameAnnotation: vObjectMeta.Name, - translate.NamespaceAnnotation: vObjectMeta.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Service").String(), + translate.NameAnnotation: vObjectMeta.Name, + translate.NamespaceAnnotation: vObjectMeta.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Service").String(), + translate.HostNamespaceAnnotation: "test", + translate.HostNameAnnotation: translate.Default.HostName(nil, "testservice", "testns").Name, }, Labels: map[string]string{ translate.NamespaceLabel: vObjectMeta.Namespace, @@ -88,6 +90,8 @@ func TestSync(t *testing.T) { translate.NamespaceAnnotation: vObjectMeta.Namespace, translate.UIDAnnotation: "", translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Service").String(), + translate.HostNamespaceAnnotation: pObjectMeta.Namespace, + translate.HostNameAnnotation: pObjectMeta.Name, translate.ManagedAnnotationsAnnotation: "a", "a": "b", }, diff --git a/pkg/controllers/resources/storageclasses/syncer_test.go b/pkg/controllers/resources/storageclasses/syncer_test.go index 94dc8a75ea..eecd659c8d 100644 --- a/pkg/controllers/resources/storageclasses/syncer_test.go +++ b/pkg/controllers/resources/storageclasses/syncer_test.go @@ -35,9 +35,10 @@ func TestSync(t *testing.T) { translate.MarkerLabel: translate.VClusterName, }, Annotations: map[string]string{ - translate.NameAnnotation: "testsc", - translate.UIDAnnotation: "", - translate.KindAnnotation: storagev1.SchemeGroupVersion.WithKind("StorageClass").String(), + translate.NameAnnotation: "testsc", + translate.UIDAnnotation: "", + translate.KindAnnotation: storagev1.SchemeGroupVersion.WithKind("StorageClass").String(), + translate.HostNameAnnotation: translate.Default.HostNameCluster(vObjectMeta.Name), }, }, Provisioner: "my-provisioner", @@ -56,9 +57,10 @@ func TestSync(t *testing.T) { translate.MarkerLabel: translate.VClusterName, }, Annotations: map[string]string{ - translate.NameAnnotation: "testsc", - translate.UIDAnnotation: "", - translate.KindAnnotation: storagev1.SchemeGroupVersion.WithKind("StorageClass").String(), + translate.NameAnnotation: "testsc", + translate.UIDAnnotation: "", + translate.KindAnnotation: storagev1.SchemeGroupVersion.WithKind("StorageClass").String(), + translate.HostNameAnnotation: translate.Default.HostNameCluster(vObjectMeta.Name), }, }, Provisioner: "my-provisioner", diff --git a/pkg/controllers/resources/volumesnapshots/volumesnapshotcontents/syncer_test.go b/pkg/controllers/resources/volumesnapshots/volumesnapshotcontents/syncer_test.go index 5971f975b5..13577e3033 100644 --- a/pkg/controllers/resources/volumesnapshots/volumesnapshotcontents/syncer_test.go +++ b/pkg/controllers/resources/volumesnapshots/volumesnapshotcontents/syncer_test.go @@ -69,9 +69,10 @@ func TestSync(t *testing.T) { Name: translate.Default.HostNameCluster(vPreProvisioned.Name), ResourceVersion: "12345", Annotations: map[string]string{ - translate.NameAnnotation: vObjectMeta.Name, - translate.UIDAnnotation: "", - translate.KindAnnotation: volumesnapshotv1.SchemeGroupVersion.WithKind("VolumeSnapshotContent").String(), + translate.NameAnnotation: vObjectMeta.Name, + translate.UIDAnnotation: "", + translate.KindAnnotation: volumesnapshotv1.SchemeGroupVersion.WithKind("VolumeSnapshotContent").String(), + translate.HostNameAnnotation: translate.Default.HostNameCluster(vPreProvisioned.Name), }, } pPreProvisioned := &volumesnapshotv1.VolumeSnapshotContent{ diff --git a/pkg/controllers/resources/volumesnapshots/volumesnapshots/syncer_test.go b/pkg/controllers/resources/volumesnapshots/volumesnapshots/syncer_test.go index 5a14dfb104..484e5396ba 100644 --- a/pkg/controllers/resources/volumesnapshots/volumesnapshots/syncer_test.go +++ b/pkg/controllers/resources/volumesnapshots/volumesnapshots/syncer_test.go @@ -60,10 +60,12 @@ func TestSync(t *testing.T) { Namespace: targetNamespace, ResourceVersion: "1234", Annotations: map[string]string{ - translate.NameAnnotation: vObjectMeta.Name, - translate.NamespaceAnnotation: vObjectMeta.Namespace, - translate.UIDAnnotation: "", - translate.KindAnnotation: volumesnapshotv1.SchemeGroupVersion.WithKind("VolumeSnapshot").String(), + translate.NameAnnotation: vObjectMeta.Name, + translate.NamespaceAnnotation: vObjectMeta.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: volumesnapshotv1.SchemeGroupVersion.WithKind("VolumeSnapshot").String(), + translate.HostNamespaceAnnotation: targetNamespace, + translate.HostNameAnnotation: translate.Default.HostName(nil, vObjectMeta.Name, vObjectMeta.Namespace).Name, }, Labels: map[string]string{ translate.MarkerLabel: translate.VClusterName, diff --git a/pkg/mappings/generic/mapper.go b/pkg/mappings/generic/mapper.go index 034ea0cc73..846ed62de0 100644 --- a/pkg/mappings/generic/mapper.go +++ b/pkg/mappings/generic/mapper.go @@ -78,26 +78,56 @@ func (n *mapper) VirtualToHost(ctx *synccontext.SyncContext, req types.Namespace } func (n *mapper) HostToVirtual(ctx *synccontext.SyncContext, req types.NamespacedName, pObj client.Object) (retName types.NamespacedName) { - if pObj != nil { - pAnnotations := pObj.GetAnnotations() - if pAnnotations[translate.NameAnnotation] != "" { - // check if kind matches - gvk, ok := pAnnotations[translate.KindAnnotation] - if !ok || n.gvk.String() == gvk { - return types.NamespacedName{ - Namespace: pAnnotations[translate.NamespaceAnnotation], - Name: pAnnotations[translate.NameAnnotation], - } - } - } + vName := TryToTranslateBackByAnnotations(ctx, req, pObj, n.gvk) + if vName.Name != "" { + return vName + } + + return TryToTranslateBackByName(ctx, req, n.gvk) +} + +func TryToTranslateBackByAnnotations(ctx *synccontext.SyncContext, req types.NamespacedName, pObj client.Object, objectGvk schema.GroupVersionKind) types.NamespacedName { + if pObj == nil { + return types.NamespacedName{} } - return TryToTranslateBack(ctx, req, n.gvk) + // check if name annotation is there + pAnnotations := pObj.GetAnnotations() + if pAnnotations[translate.NameAnnotation] == "" { + return types.NamespacedName{} + } + + // make sure kind matches + gvk, ok := pAnnotations[translate.KindAnnotation] + if ok && objectGvk.String() != gvk { + return types.NamespacedName{} + } + + // make sure host name matches + pName, ok := pAnnotations[translate.HostNameAnnotation] + if ok && pName != pObj.GetName() { + return types.NamespacedName{} + } + + // make sure host namespace matches + pNamespace, ok := pAnnotations[translate.HostNamespaceAnnotation] + if ok && pNamespace != pObj.GetNamespace() { + return types.NamespacedName{} + } + + klog.FromContext(ctx).V(1).Info("Translated back name/namespace via annotations method", "req", req.String(), "ret", types.NamespacedName{ + Namespace: pAnnotations[translate.NamespaceAnnotation], + Name: pAnnotations[translate.NameAnnotation], + }.String()) + return types.NamespacedName{ + Namespace: pAnnotations[translate.NamespaceAnnotation], + Name: pAnnotations[translate.NameAnnotation], + } } -// TryToTranslateBack is used to find out the name mapping automatically in certain scenarios, this doesn't always +// TryToTranslateBackByName is used to find out the name mapping automatically in certain scenarios, this doesn't always // work, but for some cases this is pretty useful. -func TryToTranslateBack(ctx *synccontext.SyncContext, req types.NamespacedName, gvk schema.GroupVersionKind) types.NamespacedName { +func TryToTranslateBackByName(ctx *synccontext.SyncContext, req types.NamespacedName, gvk schema.GroupVersionKind) types.NamespacedName { if ctx == nil || ctx.Config == nil || ctx.Mappings == nil { return types.NamespacedName{} } diff --git a/pkg/mappings/generic/mapper_test.go b/pkg/mappings/generic/mapper_test.go index 0333bb9f3e..c73b393ec8 100644 --- a/pkg/mappings/generic/mapper_test.go +++ b/pkg/mappings/generic/mapper_test.go @@ -8,14 +8,144 @@ import ( config2 "github.com/loft-sh/vcluster/pkg/config" "github.com/loft-sh/vcluster/pkg/mappings" "github.com/loft-sh/vcluster/pkg/mappings/store" + "github.com/loft-sh/vcluster/pkg/scheme" "github.com/loft-sh/vcluster/pkg/syncer/synccontext" "github.com/loft-sh/vcluster/pkg/util/translate" "gotest.tools/assert" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" ) -func TestTryToTranslateBack(t *testing.T) { +func TestTryToTranslateBackByAnnotations(t *testing.T) { + type testCase struct { + Name string + + Object client.Object + + Result types.NamespacedName + } + testCases := []testCase{ + { + Name: "Simple", + + Object: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + translate.NameAnnotation: "virtual-name", + translate.NamespaceAnnotation: "virtual-namespace", + }, + }, + }, + + Result: types.NamespacedName{Name: "virtual-name", Namespace: "virtual-namespace"}, + }, + { + Name: "Simple with other annotations", + + Object: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "host-name", + Namespace: "host-namespace", + Annotations: map[string]string{ + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.NameAnnotation: "virtual-name", + translate.NamespaceAnnotation: "virtual-namespace", + translate.HostNameAnnotation: "host-name", + translate.HostNamespaceAnnotation: "host-namespace", + }, + }, + }, + + Result: types.NamespacedName{Name: "virtual-name", Namespace: "virtual-namespace"}, + }, + { + Name: "Wrong Kind", + + Object: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "host-name", + Namespace: "host-namespace", + Annotations: map[string]string{ + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Pod").String(), + translate.NameAnnotation: "virtual-name", + translate.NamespaceAnnotation: "virtual-namespace", + translate.HostNameAnnotation: "host-name", + translate.HostNamespaceAnnotation: "host-namespace", + }, + }, + }, + }, + { + Name: "Wrong host namespace", + + Object: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "host-name", + Namespace: "host-namespace", + Annotations: map[string]string{ + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.NameAnnotation: "virtual-name", + translate.NamespaceAnnotation: "virtual-namespace", + translate.HostNameAnnotation: "host-name", + translate.HostNamespaceAnnotation: "host-namespace-does-not-exist", + }, + }, + }, + }, + { + Name: "Wrong host name", + + Object: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "host-name", + Namespace: "host-namespace", + Annotations: map[string]string{ + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.NameAnnotation: "virtual-name", + translate.NamespaceAnnotation: "virtual-namespace", + translate.HostNameAnnotation: "host-name-1", + translate.HostNamespaceAnnotation: "host-namespace", + }, + }, + }, + }, + { + Name: "Name missing", + + Object: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "host-name", + Namespace: "host-namespace", + Annotations: map[string]string{ + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.NamespaceAnnotation: "virtual-namespace", + translate.HostNameAnnotation: "host-name", + translate.HostNamespaceAnnotation: "host-namespace", + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + // check recording + syncContext := &synccontext.SyncContext{ + Context: context.TODO(), + } + + gvk, err := apiutil.GVKForObject(testCase.Object, scheme.Scheme) + assert.NilError(t, err) + result := TryToTranslateBackByAnnotations(syncContext, types.NamespacedName{Name: testCase.Object.GetName(), Namespace: testCase.Object.GetNamespace()}, testCase.Object, gvk) + assert.Equal(t, testCase.Result.String(), result.String()) + }) + } +} + +func TestTryToTranslateBackByName(t *testing.T) { targetNamespace := "target-namespace" translate.Default = translate.NewSingleNamespaceTranslator(targetNamespace) gvk := corev1.SchemeGroupVersion.WithKind("Secret") @@ -43,12 +173,12 @@ func TestTryToTranslateBack(t *testing.T) { HostName: types.NamespacedName{Name: "host-name", Namespace: "host-namespace"}, } syncContext.Context = synccontext.WithMapping(syncContext.Context, secretMapping) - assert.Equal(t, TryToTranslateBack(syncContext, secretMapping.HostName, gvk).String(), types.NamespacedName{}.String()) + assert.Equal(t, TryToTranslateBackByName(syncContext, secretMapping.HostName, gvk).String(), types.NamespacedName{}.String()) // single-namespace translate host name short secretMapping.HostName = translate.Default.HostNameShort(syncContext, secretMapping.VirtualName.Name, secretMapping.VirtualName.Namespace) syncContext.Context = synccontext.WithMapping(syncContext.Context, secretMapping) - assert.Equal(t, TryToTranslateBack(syncContext, secretMapping.HostName, gvk).String(), secretMapping.VirtualName.String()) + assert.Equal(t, TryToTranslateBackByName(syncContext, secretMapping.HostName, gvk).String(), secretMapping.VirtualName.String()) // multi-namespace mode namespaceMapper, err := NewMirrorMapper(&corev1.Namespace{}) @@ -60,5 +190,5 @@ func TestTryToTranslateBack(t *testing.T) { Namespace: "test", Name: "test", } - assert.Equal(t, TryToTranslateBack(syncContext, req, gvk).String(), req.String()) + assert.Equal(t, TryToTranslateBackByName(syncContext, req, gvk).String(), req.String()) } diff --git a/pkg/syncer/syncer_test.go b/pkg/syncer/syncer_test.go index ebe574dfe2..b21473315b 100644 --- a/pkg/syncer/syncer_test.go +++ b/pkg/syncer/syncer_test.go @@ -195,10 +195,12 @@ func TestController(t *testing.T) { Name: translator.HostName(nil, "a", namespaceInVClusterA).Name, Namespace: testingutil.DefaultTestTargetNamespace, Annotations: map[string]string{ - translate.NameAnnotation: "a", - translate.NamespaceAnnotation: namespaceInVClusterA, - translate.UIDAnnotation: "123", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.NameAnnotation: "a", + translate.NamespaceAnnotation: namespaceInVClusterA, + translate.UIDAnnotation: "123", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.HostNameAnnotation: translator.HostName(nil, "a", namespaceInVClusterA).Name, + translate.HostNamespaceAnnotation: testingutil.DefaultTestTargetNamespace, }, Labels: map[string]string{ translate.NamespaceLabel: namespaceInVClusterA, @@ -352,10 +354,12 @@ func TestReconcile(t *testing.T) { Name: translator.HostName(nil, "a", namespaceInVClusterA).Name, Namespace: testingutil.DefaultTestTargetNamespace, Annotations: map[string]string{ - translate.NameAnnotation: "a", - translate.NamespaceAnnotation: namespaceInVClusterA, - translate.UIDAnnotation: "123", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.NameAnnotation: "a", + translate.NamespaceAnnotation: namespaceInVClusterA, + translate.UIDAnnotation: "123", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.HostNamespaceAnnotation: testingutil.DefaultTestTargetNamespace, + translate.HostNameAnnotation: translator.HostName(nil, "a", namespaceInVClusterA).Name, }, Labels: map[string]string{ translate.NamespaceLabel: namespaceInVClusterA, @@ -426,11 +430,13 @@ func TestReconcile(t *testing.T) { Name: translator.HostName(nil, "a", namespaceInVClusterA).Name, Namespace: testingutil.DefaultTestTargetNamespace, Annotations: map[string]string{ - "app": "existing", - translate.NameAnnotation: "a", - translate.NamespaceAnnotation: namespaceInVClusterA, - translate.UIDAnnotation: "123", - translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + "app": "existing", + translate.NameAnnotation: "a", + translate.NamespaceAnnotation: namespaceInVClusterA, + translate.UIDAnnotation: "123", + translate.KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), + translate.HostNameAnnotation: translator.HostName(nil, "a", namespaceInVClusterA).Name, + translate.HostNamespaceAnnotation: testingutil.DefaultTestTargetNamespace, }, Labels: map[string]string{ translate.NamespaceLabel: namespaceInVClusterA, diff --git a/pkg/util/translate/multi_namespace.go b/pkg/util/translate/multi_namespace.go index 4f057483e6..390d7a8c44 100644 --- a/pkg/util/translate/multi_namespace.go +++ b/pkg/util/translate/multi_namespace.go @@ -69,6 +69,13 @@ func (s *multiNamespace) IsManaged(ctx *synccontext.SyncContext, pObj client.Obj } } + // check if host name / namespace matches actual name / namespace + if pObj.GetAnnotations()[HostNameAnnotation] != "" && pObj.GetAnnotations()[HostNameAnnotation] != pObj.GetName() { + return false + } else if pObj.GetAnnotations()[HostNamespaceAnnotation] != "" && pObj.GetAnnotations()[HostNamespaceAnnotation] != pObj.GetNamespace() { + return false + } + return true } diff --git a/pkg/util/translate/single_namespace.go b/pkg/util/translate/single_namespace.go index fc170a7338..99231dd652 100644 --- a/pkg/util/translate/single_namespace.go +++ b/pkg/util/translate/single_namespace.go @@ -132,6 +132,13 @@ func (s *singleNamespace) IsManaged(ctx *synccontext.SyncContext, pObj client.Ob } } + // check if host name / namespace matches actual name / namespace + if pObj.GetAnnotations()[HostNameAnnotation] != "" && pObj.GetAnnotations()[HostNameAnnotation] != pObj.GetName() { + return false + } else if pObj.GetAnnotations()[HostNamespaceAnnotation] != "" && pObj.GetAnnotations()[HostNamespaceAnnotation] != pObj.GetNamespace() { + return false + } + return true } diff --git a/pkg/util/translate/translate.go b/pkg/util/translate/translate.go index c024e05aa7..0c48af78c3 100644 --- a/pkg/util/translate/translate.go +++ b/pkg/util/translate/translate.go @@ -53,7 +53,7 @@ func CopyObjectWithName[T client.Object](obj T, name types.NamespacedName, setOw func HostMetadata[T client.Object](vObj T, name types.NamespacedName, excludedAnnotations ...string) T { pObj := CopyObjectWithName(vObj, name, true) - pObj.SetAnnotations(HostAnnotations(vObj, nil, excludedAnnotations...)) + pObj.SetAnnotations(HostAnnotations(vObj, pObj, excludedAnnotations...)) pObj.SetLabels(HostLabels(vObj, nil)) return pObj } @@ -66,7 +66,7 @@ func VirtualMetadata[T client.Object](pObj T, name types.NamespacedName, exclude } func VirtualAnnotations(pObj, vObj client.Object, excluded ...string) map[string]string { - excluded = append(excluded, NameAnnotation, UIDAnnotation, KindAnnotation, NamespaceAnnotation, ManagedAnnotationsAnnotation, ManagedLabelsAnnotation) + excluded = append(excluded, NameAnnotation, NamespaceAnnotation, HostNameAnnotation, HostNamespaceAnnotation, UIDAnnotation, KindAnnotation, ManagedAnnotationsAnnotation, ManagedLabelsAnnotation) var toAnnotations map[string]string if vObj != nil { toAnnotations = vObj.GetAnnotations() @@ -100,7 +100,7 @@ func copyMaps(fromMap, toMap map[string]string, excludeKey func(string) bool) ma } func HostAnnotations(vObj, pObj client.Object, excluded ...string) map[string]string { - excluded = append(excluded, NameAnnotation, UIDAnnotation, KindAnnotation, NamespaceAnnotation) + excluded = append(excluded, NameAnnotation, HostNameAnnotation, HostNamespaceAnnotation, UIDAnnotation, KindAnnotation, NamespaceAnnotation) toAnnotations := map[string]string{} if pObj != nil { toAnnotations = pObj.GetAnnotations() @@ -109,6 +109,12 @@ func HostAnnotations(vObj, pObj client.Object, excluded ...string) map[string]st retMap := applyAnnotations(vObj.GetAnnotations(), toAnnotations, excluded...) retMap[NameAnnotation] = vObj.GetName() retMap[UIDAnnotation] = string(vObj.GetUID()) + if pObj != nil { + retMap[HostNameAnnotation] = pObj.GetName() + if pObj.GetNamespace() != "" { + retMap[HostNamespaceAnnotation] = pObj.GetNamespace() + } + } if vObj.GetNamespace() == "" { delete(retMap, NamespaceAnnotation) } else { diff --git a/pkg/util/translate/translate_test.go b/pkg/util/translate/translate_test.go index b4a97b3706..ffeec23d00 100644 --- a/pkg/util/translate/translate_test.go +++ b/pkg/util/translate/translate_test.go @@ -80,6 +80,7 @@ func TestAnnotations(t *testing.T) { ManagedAnnotationsAnnotation: "test", KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), NameAnnotation: "", + HostNameAnnotation: "", UIDAnnotation: "", }, pObj.Annotations) @@ -97,6 +98,7 @@ func TestAnnotations(t *testing.T) { ManagedAnnotationsAnnotation: "other\ntest", KindAnnotation: corev1.SchemeGroupVersion.WithKind("Secret").String(), NameAnnotation: "", + HostNameAnnotation: "", UIDAnnotation: "", }, pObj.Annotations) } diff --git a/pkg/util/translate/types.go b/pkg/util/translate/types.go index 0103544662..edf2dbba63 100644 --- a/pkg/util/translate/types.go +++ b/pkg/util/translate/types.go @@ -7,10 +7,12 @@ import ( ) var ( - NamespaceAnnotation = "vcluster.loft.sh/object-namespace" - NameAnnotation = "vcluster.loft.sh/object-name" - UIDAnnotation = "vcluster.loft.sh/object-uid" - KindAnnotation = "vcluster.loft.sh/object-kind" + NamespaceAnnotation = "vcluster.loft.sh/object-namespace" + NameAnnotation = "vcluster.loft.sh/object-name" + UIDAnnotation = "vcluster.loft.sh/object-uid" + KindAnnotation = "vcluster.loft.sh/object-kind" + HostNameAnnotation = "vcluster.loft.sh/object-host-name" + HostNamespaceAnnotation = "vcluster.loft.sh/object-host-namespace" ) var ( From 1670e74b116893f4dd2a8f1b7cf36600b15fcf2c Mon Sep 17 00:00:00 2001 From: Fabian Kramm Date: Tue, 20 Aug 2024 18:30:39 +0200 Subject: [PATCH 2/4] refactor: mapper --- pkg/mappings/generic/mapper.go | 86 +++++++++++++++ pkg/mappings/generic/mapper_test.go | 165 ++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) diff --git a/pkg/mappings/generic/mapper.go b/pkg/mappings/generic/mapper.go index 846ed62de0..0b765f6085 100644 --- a/pkg/mappings/generic/mapper.go +++ b/pkg/mappings/generic/mapper.go @@ -2,6 +2,7 @@ package generic import ( "fmt" + "regexp" "strings" "github.com/loft-sh/vcluster/pkg/mappings" @@ -15,6 +16,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/apiutil" ) +var shortNameMatcher = regexp.MustCompile(`v[a-z0-9]{13}`) + // PhysicalNameWithObjectFunc is a definition to translate a name that also optionally expects a vObj type PhysicalNameWithObjectFunc func(ctx *synccontext.SyncContext, vName, vNamespace string, vObj client.Object) types.NamespacedName @@ -159,6 +162,28 @@ func TryToTranslateBackByName(ctx *synccontext.SyncContext, req types.Namespaced } } + // try single-namespace mode assumptions + vName := tryToMatchHostNameShort(ctx, req) + if vName.Name != "" { + return vName + } + + // try searching mapping store for host name short + vName = tryToFindHostNameShortInStore(ctx, req) + if vName.Name != "" { + return vName + } + + // try searching mapping store for host name + vName = tryToFindHostNameInStore(ctx, req) + if vName.Name != "" { + return vName + } + + return types.NamespacedName{} +} + +func tryToMatchHostNameShort(ctx *synccontext.SyncContext, req types.NamespacedName) types.NamespacedName { // if single namespace mode and the owner object was translated via NameShort, we can try to find that name // within the host name and assume it's the same namespace / name nameMapping, ok := synccontext.MappingFrom(ctx) @@ -185,6 +210,67 @@ func TryToTranslateBackByName(ctx *synccontext.SyncContext, req types.Namespaced } } +func tryToFindHostNameInStore(ctx *synccontext.SyncContext, pName types.NamespacedName) types.NamespacedName { + for gvk := range ctx.Mappings.List() { + // try to find match in store + vName, ok := ctx.Mappings.Store().HostToVirtualName(ctx, synccontext.Object{ + GroupVersionKind: gvk, + NamespacedName: pName, + }) + if !ok || vName.Name == "" || vName.Namespace == "" { + continue + } + + // check if this is actually a HostNameShort + if pName.String() != translate.Default.HostName(ctx, vName.Name, vName.Namespace).String() { + continue + } + + // replace pName.Name with vName.Name + return types.NamespacedName{ + Name: vName.Name, + Namespace: vName.Namespace, + } + } + + return types.NamespacedName{} +} + +func tryToFindHostNameShortInStore(ctx *synccontext.SyncContext, pName types.NamespacedName) types.NamespacedName { + // we search for strings that are exact length 10 and have no - or . in it + matches := shortNameMatcher.FindAllString(pName.Name, -1) + + // loop over all mapping gvk's + for _, match := range matches { + for gvk := range ctx.Mappings.List() { + // try to find match in store + vName, ok := ctx.Mappings.Store().HostToVirtualName(ctx, synccontext.Object{ + GroupVersionKind: gvk, + NamespacedName: types.NamespacedName{ + Namespace: pName.Namespace, + Name: match, + }, + }) + if !ok || vName.Name == "" || vName.Namespace == "" { + continue + } + + // check if this is actually a HostNameShort + if match != translate.Default.HostNameShort(ctx, vName.Name, vName.Namespace).Name { + continue + } + + // replace pName.Name with vName.Name + return types.NamespacedName{ + Name: strings.ReplaceAll(pName.Name, match, vName.Name), + Namespace: vName.Namespace, + } + } + } + + return types.NamespacedName{} +} + func (n *mapper) IsManaged(ctx *synccontext.SyncContext, pObj client.Object) (bool, error) { return translate.Default.IsManaged(ctx, pObj), nil } diff --git a/pkg/mappings/generic/mapper_test.go b/pkg/mappings/generic/mapper_test.go index c73b393ec8..a22e723f7f 100644 --- a/pkg/mappings/generic/mapper_test.go +++ b/pkg/mappings/generic/mapper_test.go @@ -10,6 +10,7 @@ import ( "github.com/loft-sh/vcluster/pkg/mappings/store" "github.com/loft-sh/vcluster/pkg/scheme" "github.com/loft-sh/vcluster/pkg/syncer/synccontext" + testingutil "github.com/loft-sh/vcluster/pkg/util/testing" "github.com/loft-sh/vcluster/pkg/util/translate" "gotest.tools/assert" corev1 "k8s.io/api/core/v1" @@ -145,6 +146,170 @@ func TestTryToTranslateBackByAnnotations(t *testing.T) { } } +func TestTryToTranslateBackByStore(t *testing.T) { + translate.Default = translate.NewSingleNamespaceTranslator(testingutil.DefaultTestTargetNamespace) + + type testCase struct { + Name string + + Mappings []*store.Mapping + + Mapping synccontext.Object + + Expected types.NamespacedName + } + testCases := []testCase{ + { + Name: "Simple", + + Mappings: []*store.Mapping{ + { + NameMapping: synccontext.NameMapping{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Pod"), + VirtualName: types.NamespacedName{Name: "test", Namespace: "test"}, + HostName: translate.Default.HostNameShort(nil, "test", "test"), + }, + }, + }, + + Mapping: synccontext.Object{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Secret"), + NamespacedName: translate.Default.HostNameShort(nil, "test", "test"), + }, + + Expected: types.NamespacedName{Name: "test", Namespace: "test"}, + }, + { + Name: "Wrong name mapping", + + Mappings: []*store.Mapping{ + { + NameMapping: synccontext.NameMapping{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Pod"), + VirtualName: types.NamespacedName{Name: "test123", Namespace: "test"}, + HostName: translate.Default.HostNameShort(nil, "test", "test"), + }, + }, + }, + + Mapping: synccontext.Object{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Secret"), + NamespacedName: translate.Default.HostNameShort(nil, "test", "test"), + }, + }, + { + Name: "Match within name", + + Mappings: []*store.Mapping{ + { + NameMapping: synccontext.NameMapping{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Pod"), + VirtualName: types.NamespacedName{Name: "test", Namespace: "test"}, + HostName: translate.Default.HostNameShort(nil, "test", "test"), + }, + }, + }, + + Mapping: synccontext.Object{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Secret"), + NamespacedName: types.NamespacedName{ + Namespace: translate.Default.HostNameShort(nil, "test", "test").Namespace, + Name: "testme-" + translate.Default.HostNameShort(nil, "test", "test").Name + "-testme", + }, + }, + + Expected: types.NamespacedName{Name: "testme-test-testme", Namespace: "test"}, + }, + { + Name: "Match multiple within name", + + Mappings: []*store.Mapping{ + { + NameMapping: synccontext.NameMapping{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Pod"), + VirtualName: types.NamespacedName{Name: "test", Namespace: "test"}, + HostName: translate.Default.HostNameShort(nil, "test", "test"), + }, + }, + }, + + Mapping: synccontext.Object{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Secret"), + NamespacedName: types.NamespacedName{ + Namespace: translate.Default.HostNameShort(nil, "test", "test").Namespace, + Name: "testme-" + translate.Default.HostNameShort(nil, "test", "test").Name + "-testme-" + translate.Default.HostNameShort(nil, "test", "test").Name, + }, + }, + + Expected: types.NamespacedName{Name: "testme-test-testme-test", Namespace: "test"}, + }, + { + Name: "Translate back regular name", + + Mappings: []*store.Mapping{ + { + NameMapping: synccontext.NameMapping{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Pod"), + VirtualName: types.NamespacedName{Name: "test", Namespace: "test"}, + HostName: translate.Default.HostName(nil, "test", "test"), + }, + }, + }, + + Mapping: synccontext.Object{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Secret"), + NamespacedName: translate.Default.HostName(nil, "test", "test"), + }, + + Expected: types.NamespacedName{Name: "test", Namespace: "test"}, + }, + { + Name: "Don't translate back regular name in between", + + Mappings: []*store.Mapping{ + { + NameMapping: synccontext.NameMapping{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Pod"), + VirtualName: types.NamespacedName{Name: "test", Namespace: "test"}, + HostName: translate.Default.HostName(nil, "test", "test"), + }, + }, + }, + + Mapping: synccontext.Object{ + GroupVersionKind: corev1.SchemeGroupVersion.WithKind("Secret"), + NamespacedName: types.NamespacedName{ + Namespace: translate.Default.HostName(nil, "test", "test").Namespace, + Name: "testme-" + translate.Default.HostName(nil, "test", "test").Name, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + storeBackend := store.NewMemoryBackend(testCase.Mappings...) + mappingsStore, err := store.NewStore(context.TODO(), nil, nil, storeBackend) + assert.NilError(t, err) + + // check recording + syncContext := &synccontext.SyncContext{ + Context: context.TODO(), + Config: testingutil.NewFakeConfig(), + Mappings: mappings.NewMappingsRegistry(mappingsStore), + } + for _, mapping := range testCase.Mappings { + if !syncContext.Mappings.Has(mapping.GroupVersionKind) { + err = syncContext.Mappings.AddMapper(&fakeMapper{gvk: mapping.GroupVersionKind}) + assert.NilError(t, err) + } + } + + assert.Equal(t, TryToTranslateBackByName(syncContext, testCase.Mapping.NamespacedName, testCase.Mapping.GroupVersionKind).String(), testCase.Expected.String()) + }) + } +} + func TestTryToTranslateBackByName(t *testing.T) { targetNamespace := "target-namespace" translate.Default = translate.NewSingleNamespaceTranslator(targetNamespace) From f42b41bcc2c833050cf451050e32422c62b8cc22 Mon Sep 17 00:00:00 2001 From: Fabian Kramm Date: Tue, 20 Aug 2024 18:31:00 +0200 Subject: [PATCH 3/4] fix: service selector sync --- pkg/controllers/resources/services/syncer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controllers/resources/services/syncer.go b/pkg/controllers/resources/services/syncer.go index c002860429..8659ce81fe 100644 --- a/pkg/controllers/resources/services/syncer.go +++ b/pkg/controllers/resources/services/syncer.go @@ -153,7 +153,7 @@ func (s *serviceSyncer) Sync(ctx *synccontext.SyncContext, event *synccontext.Sy // translate selector if event.Source == synccontext.SyncEventSourceHost { - event.Host.Spec.Selector = translate.VirtualLabelsMap(event.Host.Spec.Selector, event.Virtual.Spec.Selector) + event.Virtual.Spec.Selector = translate.VirtualLabelsMap(event.Host.Spec.Selector, event.Virtual.Spec.Selector) } else { event.Host.Spec.Selector = translate.HostLabelsMap(event.Virtual.Spec.Selector, event.Host.Spec.Selector, event.Virtual.Namespace, false) } From 76185ff3fb16a22f1090630ae5177214a5b5e2be Mon Sep 17 00:00:00 2001 From: Fabian Kramm Date: Tue, 20 Aug 2024 18:31:30 +0200 Subject: [PATCH 4/4] refactor: only rewrite "release" label in single-namespace-mode --- pkg/mappings/generic/mapper.go | 2 +- pkg/util/translate/labels.go | 16 ++---- pkg/util/translate/multi_namespace.go | 9 ++++ pkg/util/translate/single_namespace.go | 12 +++++ pkg/util/translate/translate_test.go | 67 ++++++++++++++++++++++++++ pkg/util/translate/types.go | 3 ++ 6 files changed, 95 insertions(+), 14 deletions(-) diff --git a/pkg/mappings/generic/mapper.go b/pkg/mappings/generic/mapper.go index 0b765f6085..e167a81770 100644 --- a/pkg/mappings/generic/mapper.go +++ b/pkg/mappings/generic/mapper.go @@ -221,7 +221,7 @@ func tryToFindHostNameInStore(ctx *synccontext.SyncContext, pName types.Namespac continue } - // check if this is actually a HostNameShort + // check if this is actually a HostName if pName.String() != translate.Default.HostName(ctx, vName.Name, vName.Namespace).String() { continue } diff --git a/pkg/util/translate/labels.go b/pkg/util/translate/labels.go index d2f0356511..c2c4c87f17 100644 --- a/pkg/util/translate/labels.go +++ b/pkg/util/translate/labels.go @@ -7,18 +7,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -var LabelsToTranslate = map[string]bool{ - // rewrite release - VClusterReleaseLabel: true, - - // namespace, marker & controlled-by - NamespaceLabel: true, - MarkerLabel: true, - ControllerLabel: true, -} - func IsTranslatedLabel(label string) (string, bool) { - for k := range LabelsToTranslate { + for k := range Default.LabelsToTranslate() { if convertLabelKeyWithPrefix(LabelPrefix, k) == label { return k, true } @@ -27,7 +17,7 @@ func IsTranslatedLabel(label string) (string, bool) { } func HostLabel(vLabel string) string { - if LabelsToTranslate[vLabel] { + if Default.LabelsToTranslate()[vLabel] { return convertLabelKeyWithPrefix(LabelPrefix, vLabel) } @@ -35,7 +25,7 @@ func HostLabel(vLabel string) string { } func VirtualLabel(pLabel string) (string, bool) { - if LabelsToTranslate[pLabel] { + if Default.LabelsToTranslate()[pLabel] { return "", false } diff --git a/pkg/util/translate/multi_namespace.go b/pkg/util/translate/multi_namespace.go index 390d7a8c44..7af6ccfb15 100644 --- a/pkg/util/translate/multi_namespace.go +++ b/pkg/util/translate/multi_namespace.go @@ -79,6 +79,15 @@ func (s *multiNamespace) IsManaged(ctx *synccontext.SyncContext, pObj client.Obj return true } +func (s *multiNamespace) LabelsToTranslate() map[string]bool { + return map[string]bool{ + // namespace, marker & controlled-by + NamespaceLabel: true, + MarkerLabel: true, + ControllerLabel: true, + } +} + func (s *multiNamespace) IsTargetedNamespace(ctx *synccontext.SyncContext, pNamespace string) bool { if _, ok := pro.HostNamespaceMatchesMapping(ctx, pNamespace); ok { return true diff --git a/pkg/util/translate/single_namespace.go b/pkg/util/translate/single_namespace.go index 99231dd652..91d0fb3fd9 100644 --- a/pkg/util/translate/single_namespace.go +++ b/pkg/util/translate/single_namespace.go @@ -150,6 +150,18 @@ func (s *singleNamespace) IsTargetedNamespace(ctx *synccontext.SyncContext, pNam return pNamespace == s.targetNamespace } +func (s *singleNamespace) LabelsToTranslate() map[string]bool { + return map[string]bool{ + // rewrite release + VClusterReleaseLabel: true, + + // namespace, marker & controlled-by + NamespaceLabel: true, + MarkerLabel: true, + ControllerLabel: true, + } +} + func (s *singleNamespace) HostNamespace(ctx *synccontext.SyncContext, vNamespace string) string { if vNamespace == "" { return "" diff --git a/pkg/util/translate/translate_test.go b/pkg/util/translate/translate_test.go index ffeec23d00..964b62e489 100644 --- a/pkg/util/translate/translate_test.go +++ b/pkg/util/translate/translate_test.go @@ -21,6 +21,21 @@ func TestVirtualLabels(t *testing.T) { "test123": "test123", "release": "vcluster", }, vMap) + + Default = NewMultiNamespaceTranslator("test") + vMap = VirtualLabelsMap(map[string]string{ + "test": "test", + "test123": "test123", + "vcluster.loft.sh/label-suffix-x-a4d451ec23": "vcluster", + }, nil) + assert.DeepEqual(t, map[string]string{ + "test": "test", + "test123": "test123", + "vcluster.loft.sh/label-suffix-x-a4d451ec23": "vcluster", + }, vMap) + + // restore Default + Default = &singleNamespace{} } func TestNotRewritingLabels(t *testing.T) { @@ -129,6 +144,58 @@ func TestRecursiveLabelsMap(t *testing.T) { } } +func TestLabelsMapMultiNamespaceMode(t *testing.T) { + Default = NewMultiNamespaceTranslator("test") + defer func() { + // restore Default + Default = &singleNamespace{} + }() + + vMap := map[string]string{ + "test": "test", + "test123": "test123", + "release": "vcluster", + "vcluster.loft.sh/label-suffix-x-a4d451ec23": "vcluster123", + } + + pMap := HostLabelsMap(vMap, nil, "test", false) + assert.DeepEqual(t, map[string]string{ + "test": "test", + "test123": "test123", + "release": "vcluster", + "vcluster.loft.sh/label-suffix-x-a4d451ec23": "vcluster123", + }, pMap) + + pMap["other"] = "other" + + vMap = VirtualLabelsMap(pMap, vMap) + assert.DeepEqual(t, map[string]string{ + "test": "test", + "test123": "test123", + "other": "other", + "release": "vcluster", + "vcluster.loft.sh/label-suffix-x-a4d451ec23": "vcluster123", + }, vMap) + + pMap = HostLabelsMap(vMap, pMap, "test", false) + assert.DeepEqual(t, map[string]string{ + "vcluster.loft.sh/label-suffix-x-a4d451ec23": "vcluster123", + "release": "vcluster", + "test": "test", + "test123": "test123", + "other": "other", + }, pMap) + + delete(vMap, "other") + pMap = HostLabelsMap(vMap, pMap, "test", false) + assert.DeepEqual(t, map[string]string{ + "vcluster.loft.sh/label-suffix-x-a4d451ec23": "vcluster123", + "release": "vcluster", + "test": "test", + "test123": "test123", + }, pMap) +} + func TestLabelsMap(t *testing.T) { vMap := map[string]string{ "test": "test", diff --git a/pkg/util/translate/types.go b/pkg/util/translate/types.go index edf2dbba63..ab17d38ecc 100644 --- a/pkg/util/translate/types.go +++ b/pkg/util/translate/types.go @@ -58,4 +58,7 @@ type Translator interface { // HostNamespace returns the host namespace for a virtual cluster object HostNamespace(ctx *synccontext.SyncContext, vNamespace string) string + + // LabelsToTranslate are the labels that should be translated + LabelsToTranslate() map[string]bool }