From ca602d6e940f1a556be593d4e468367126b8965c Mon Sep 17 00:00:00 2001 From: Fabian Kramm Date: Fri, 5 Apr 2024 11:42:07 +0200 Subject: [PATCH] fix: configmap & multi-namespace mode --- .../resources/configmaps/syncer.go | 46 ++++++++++++++----- .../resources/configmaps/translate.go | 5 +- pkg/controllers/resources/configmaps/util.go | 12 ++--- pkg/controllers/resources/pods/syncer.go | 2 +- .../resources/pods/translate/translator.go | 28 +++++++---- .../translator/namespaced_translator.go | 10 +--- .../syncer/translator/translator.go | 4 -- 7 files changed, 66 insertions(+), 41 deletions(-) diff --git a/pkg/controllers/resources/configmaps/syncer.go b/pkg/controllers/resources/configmaps/syncer.go index cf38c5f4b..07f7af383 100644 --- a/pkg/controllers/resources/configmaps/syncer.go +++ b/pkg/controllers/resources/configmaps/syncer.go @@ -23,32 +23,54 @@ import ( func New(ctx *synccontext.RegisterContext) (syncer.Object, error) { t := translator.NewNamespacedTranslator(ctx, "configmap", &corev1.ConfigMap{}) - t.SetNameTranslator(ConfigMapNameTranslator) + return &configMapSyncer{ NamespacedTranslator: t, - syncAllConfigMaps: ctx.Config.Sync.ToHost.ConfigMaps.All, + syncAllConfigMaps: ctx.Config.Sync.ToHost.ConfigMaps.All, + multiNamespaceMode: ctx.Config.Experimental.MultiNamespaceMode.Enabled, }, nil } type configMapSyncer struct { translator.NamespacedTranslator - syncAllConfigMaps bool + syncAllConfigMaps bool + multiNamespaceMode bool } -func ConfigMapNameTranslator(vNN types.NamespacedName, _ client.Object) string { - name := translate.Default.PhysicalName(vNN.Name, vNN.Namespace) - if name == "kube-root-ca.crt" { - name = translate.SafeConcatName("vcluster", "kube-root-ca.crt", "x", translate.VClusterName) +var _ syncer.IndicesRegisterer = &configMapSyncer{} + +func (s *configMapSyncer) VirtualToHost(ctx context.Context, req types.NamespacedName, vObj client.Object) types.NamespacedName { + if s.multiNamespaceMode && req.Name == "kube-root-ca.crt" { + return types.NamespacedName{ + Name: translate.SafeConcatName("vcluster", "kube-root-ca.crt", "x", translate.VClusterName), + Namespace: s.NamespacedTranslator.VirtualToHost(ctx, req, vObj).Namespace, + } } - return name + + return s.NamespacedTranslator.VirtualToHost(ctx, req, vObj) } -var _ syncer.IndicesRegisterer = &configMapSyncer{} +func (s *configMapSyncer) HostToVirtual(ctx context.Context, req types.NamespacedName, pObj client.Object) types.NamespacedName { + if s.multiNamespaceMode && req.Name == translate.SafeConcatName("vcluster", "kube-root-ca.crt", "x", translate.VClusterName) { + return types.NamespacedName{ + Name: "kube-root-ca.crt", + Namespace: s.NamespacedTranslator.HostToVirtual(ctx, req, pObj).Namespace, + } + } + + return s.NamespacedTranslator.HostToVirtual(ctx, req, pObj) +} func (s *configMapSyncer) RegisterIndices(ctx *synccontext.RegisterContext) error { - err := s.NamespacedTranslator.RegisterIndices(ctx) + err := ctx.VirtualManager.GetFieldIndexer().IndexField(ctx.Context, &corev1.ConfigMap{}, constants.IndexByPhysicalName, func(rawObj client.Object) []string { + if s.multiNamespaceMode && rawObj.GetName() == "kube-root-ca.crt" { + return []string{translate.Default.PhysicalNamespace(rawObj.GetNamespace()) + "/" + translate.SafeConcatName("vcluster", "kube-root-ca.crt", "x", translate.VClusterName)} + } + + return []string{translate.Default.PhysicalNamespace(rawObj.GetNamespace()) + "/" + translate.Default.PhysicalName(rawObj.GetName(), rawObj.GetNamespace())} + }) if err != nil { return err } @@ -56,7 +78,7 @@ func (s *configMapSyncer) RegisterIndices(ctx *synccontext.RegisterContext) erro // index pods by their used config maps return ctx.VirtualManager.GetFieldIndexer().IndexField(ctx.Context, &corev1.Pod{}, constants.IndexByConfigMap, func(rawObj client.Object) []string { pod := rawObj.(*corev1.Pod) - return ConfigNamesFromPod(pod) + return configNamesFromPod(pod) }) } @@ -128,7 +150,7 @@ func mapPods(_ context.Context, obj client.Object) []reconcile.Request { } requests := []reconcile.Request{} - names := ConfigNamesFromPod(pod) + names := configNamesFromPod(pod) for _, name := range names { splitted := strings.Split(name, "/") if len(splitted) == 2 { diff --git a/pkg/controllers/resources/configmaps/translate.go b/pkg/controllers/resources/configmaps/translate.go index 2c9090ea2..7133d8665 100644 --- a/pkg/controllers/resources/configmaps/translate.go +++ b/pkg/controllers/resources/configmaps/translate.go @@ -6,11 +6,14 @@ import ( "github.com/loft-sh/vcluster/pkg/controllers/syncer/translator" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" ) func (s *configMapSyncer) translate(ctx context.Context, vObj client.Object) *corev1.ConfigMap { - return s.TranslateMetadata(ctx, vObj).(*corev1.ConfigMap) + pObj := s.TranslateMetadata(ctx, vObj).(*corev1.ConfigMap) + pObj.SetName(s.VirtualToHost(ctx, types.NamespacedName{Name: vObj.GetName(), Namespace: vObj.GetNamespace()}, vObj).Name) + return pObj } func (s *configMapSyncer) translateUpdate(ctx context.Context, pObj, vObj *corev1.ConfigMap) *corev1.ConfigMap { diff --git a/pkg/controllers/resources/configmaps/util.go b/pkg/controllers/resources/configmaps/util.go index 02432dd31..c33e47f76 100644 --- a/pkg/controllers/resources/configmaps/util.go +++ b/pkg/controllers/resources/configmaps/util.go @@ -5,16 +5,16 @@ import ( corev1 "k8s.io/api/core/v1" ) -func ConfigNamesFromPod(pod *corev1.Pod) []string { +func configNamesFromPod(pod *corev1.Pod) []string { configMaps := []string{} for _, c := range pod.Spec.Containers { - configMaps = append(configMaps, ConfigNamesFromContainer(pod.Namespace, &c)...) + configMaps = append(configMaps, configNamesFromContainer(pod.Namespace, &c)...) } for _, c := range pod.Spec.InitContainers { - configMaps = append(configMaps, ConfigNamesFromContainer(pod.Namespace, &c)...) + configMaps = append(configMaps, configNamesFromContainer(pod.Namespace, &c)...) } for _, c := range pod.Spec.EphemeralContainers { - configMaps = append(configMaps, ConfigNamesFromEphemeralContainer(pod.Namespace, &c)...) + configMaps = append(configMaps, configNamesFromEphemeralContainer(pod.Namespace, &c)...) } for i := range pod.Spec.Volumes { if pod.Spec.Volumes[i].ConfigMap != nil { @@ -31,7 +31,7 @@ func ConfigNamesFromPod(pod *corev1.Pod) []string { return translate.UniqueSlice(configMaps) } -func ConfigNamesFromContainer(namespace string, container *corev1.Container) []string { +func configNamesFromContainer(namespace string, container *corev1.Container) []string { configNames := []string{} for _, env := range container.Env { if env.ValueFrom != nil && env.ValueFrom.ConfigMapKeyRef != nil && env.ValueFrom.ConfigMapKeyRef.Name != "" { @@ -46,7 +46,7 @@ func ConfigNamesFromContainer(namespace string, container *corev1.Container) []s return configNames } -func ConfigNamesFromEphemeralContainer(namespace string, container *corev1.EphemeralContainer) []string { +func configNamesFromEphemeralContainer(namespace string, container *corev1.EphemeralContainer) []string { configNames := []string{} for _, env := range container.Env { if env.ValueFrom != nil && env.ValueFrom.ConfigMapKeyRef != nil && env.ValueFrom.ConfigMapKeyRef.Name != "" { diff --git a/pkg/controllers/resources/pods/syncer.go b/pkg/controllers/resources/pods/syncer.go index d3e3df5f1..f640f5195 100644 --- a/pkg/controllers/resources/pods/syncer.go +++ b/pkg/controllers/resources/pods/syncer.go @@ -313,7 +313,7 @@ func (s *podSyncer) Sync(ctx *synccontext.SyncContext, pObj client.Object, vObj // translate services to environment variables serviceEnv := translatepods.ServicesToEnvironmentVariables(vPod.Spec.EnableServiceLinks, ptrServiceList, kubeIP) for i := range vPod.Spec.EphemeralContainers { - envVar, envFrom := translatepods.ContainerEnv(vPod.Spec.EphemeralContainers[i].Env, vPod.Spec.EphemeralContainers[i].EnvFrom, vPod, serviceEnv) + envVar, envFrom := s.podTranslator.TranslateContainerEnv(vPod.Spec.EphemeralContainers[i].Env, vPod.Spec.EphemeralContainers[i].EnvFrom, vPod, serviceEnv) vPod.Spec.EphemeralContainers[i].Env = envVar vPod.Spec.EphemeralContainers[i].EnvFrom = envFrom } diff --git a/pkg/controllers/resources/pods/translate/translator.go b/pkg/controllers/resources/pods/translate/translator.go index a4d8899e2..b9a424af5 100644 --- a/pkg/controllers/resources/pods/translate/translator.go +++ b/pkg/controllers/resources/pods/translate/translator.go @@ -11,7 +11,6 @@ import ( "strconv" "strings" - "github.com/loft-sh/vcluster/pkg/controllers/resources/configmaps" "github.com/loft-sh/vcluster/pkg/controllers/resources/priorityclasses" synccontext "github.com/loft-sh/vcluster/pkg/controllers/syncer/context" "github.com/loft-sh/vcluster/pkg/util/loghelper" @@ -22,7 +21,6 @@ import ( authenticationv1 "k8s.io/api/authentication/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" @@ -55,6 +53,8 @@ var ( type Translator interface { Translate(ctx context.Context, vPod *corev1.Pod, services []*corev1.Service, dnsIP string, kubeIP string) (*corev1.Pod, error) Diff(ctx context.Context, vPod, pPod *corev1.Pod) (*corev1.Pod, error) + + TranslateContainerEnv(envVar []corev1.EnvVar, envFrom []corev1.EnvFromSource, vPod *corev1.Pod, serviceEnvMap map[string]string) ([]corev1.EnvVar, []corev1.EnvFromSource) } func NewTranslator(ctx *synccontext.RegisterContext, eventRecorder record.EventRecorder) (Translator, error) { @@ -79,6 +79,8 @@ func NewTranslator(ctx *synccontext.RegisterContext, eventRecorder record.EventR defaultImageRegistry: ctx.Config.ControlPlane.Advanced.DefaultImageRegistry, + multiNamespaceMode: ctx.Config.Experimental.MultiNamespaceMode.Enabled, + serviceAccountSecretsEnabled: ctx.Config.Sync.ToHost.Pods.UseSecretsForSATokens, clusterDomain: ctx.Config.Networking.Advanced.ClusterDomain, serviceAccount: ctx.Config.ControlPlane.Advanced.WorkloadServiceAccount.Name, @@ -107,6 +109,8 @@ type translator struct { defaultImageRegistry string + multiNamespaceMode bool + // this is needed for host path mapper (legacy) mountPhysicalHostPaths bool @@ -268,7 +272,7 @@ func (t *translator) Translate(ctx context.Context, vPod *corev1.Pod, services [ // translate containers for i := range pPod.Spec.Containers { - envVar, envFrom := ContainerEnv(pPod.Spec.Containers[i].Env, pPod.Spec.Containers[i].EnvFrom, vPod, serviceEnv) + envVar, envFrom := t.TranslateContainerEnv(pPod.Spec.Containers[i].Env, pPod.Spec.Containers[i].EnvFrom, vPod, serviceEnv) pPod.Spec.Containers[i].Env = envVar pPod.Spec.Containers[i].EnvFrom = envFrom pPod.Spec.Containers[i].Image = t.imageTranslator.Translate(pPod.Spec.Containers[i].Image) @@ -276,7 +280,7 @@ func (t *translator) Translate(ctx context.Context, vPod *corev1.Pod, services [ // translate init containers for i := range pPod.Spec.InitContainers { - envVar, envFrom := ContainerEnv(pPod.Spec.InitContainers[i].Env, pPod.Spec.InitContainers[i].EnvFrom, vPod, serviceEnv) + envVar, envFrom := t.TranslateContainerEnv(pPod.Spec.InitContainers[i].Env, pPod.Spec.InitContainers[i].EnvFrom, vPod, serviceEnv) pPod.Spec.InitContainers[i].Env = envVar pPod.Spec.InitContainers[i].EnvFrom = envFrom pPod.Spec.InitContainers[i].Image = t.imageTranslator.Translate(pPod.Spec.InitContainers[i].Image) @@ -284,7 +288,7 @@ func (t *translator) Translate(ctx context.Context, vPod *corev1.Pod, services [ // translate ephemeral containers for i := range pPod.Spec.EphemeralContainers { - envVar, envFrom := ContainerEnv(pPod.Spec.EphemeralContainers[i].Env, pPod.Spec.EphemeralContainers[i].EnvFrom, vPod, serviceEnv) + envVar, envFrom := t.TranslateContainerEnv(pPod.Spec.EphemeralContainers[i].Env, pPod.Spec.EphemeralContainers[i].EnvFrom, vPod, serviceEnv) pPod.Spec.EphemeralContainers[i].Env = envVar pPod.Spec.EphemeralContainers[i].EnvFrom = envFrom pPod.Spec.EphemeralContainers[i].Image = t.imageTranslator.Translate(pPod.Spec.EphemeralContainers[i].Image) @@ -352,7 +356,11 @@ func (t *translator) translateVolumes(ctx context.Context, pPod *corev1.Pod, vPo for i := range pPod.Spec.Volumes { if pPod.Spec.Volumes[i].ConfigMap != nil { - pPod.Spec.Volumes[i].ConfigMap.Name = configmaps.ConfigMapNameTranslator(types.NamespacedName{Name: pPod.Spec.Volumes[i].ConfigMap.Name, Namespace: vPod.Namespace}, nil) + if t.multiNamespaceMode && pPod.Spec.Volumes[i].ConfigMap.Name == "kube-root-ca.crt" { + pPod.Spec.Volumes[i].ConfigMap.Name = translate.SafeConcatName("vcluster", "kube-root-ca.crt", "x", translate.VClusterName) + } else { + pPod.Spec.Volumes[i].ConfigMap.Name = translate.Default.PhysicalName(pPod.Spec.Volumes[i].ConfigMap.Name, vPod.Namespace) + } } if pPod.Spec.Volumes[i].Secret != nil { pPod.Spec.Volumes[i].Secret.SecretName = translate.Default.PhysicalName(pPod.Spec.Volumes[i].Secret.SecretName, vPod.Namespace) @@ -575,7 +583,7 @@ func translateFieldRef(fieldSelector *corev1.ObjectFieldSelector) { } } -func ContainerEnv(envVar []corev1.EnvVar, envFrom []corev1.EnvFromSource, vPod *corev1.Pod, serviceEnvMap map[string]string) ([]corev1.EnvVar, []corev1.EnvFromSource) { +func (t *translator) TranslateContainerEnv(envVar []corev1.EnvVar, envFrom []corev1.EnvFromSource, vPod *corev1.Pod, serviceEnvMap map[string]string) ([]corev1.EnvVar, []corev1.EnvFromSource) { envNameMap := make(map[string]struct{}) for j, env := range envVar { translateDownwardAPI(&envVar[j]) @@ -590,7 +598,11 @@ func ContainerEnv(envVar []corev1.EnvVar, envFrom []corev1.EnvFromSource, vPod * } for j, from := range envFrom { if from.ConfigMapRef != nil && from.ConfigMapRef.Name != "" { - envFrom[j].ConfigMapRef.Name = translate.Default.PhysicalName(from.ConfigMapRef.Name, vPod.Namespace) + if t.multiNamespaceMode && envFrom[j].ConfigMapRef.Name == "kube-root-ca.crt" { + envFrom[j].ConfigMapRef.Name = translate.SafeConcatName("vcluster", "kube-root-ca.crt", "x", translate.VClusterName) + } else { + envFrom[j].ConfigMapRef.Name = translate.Default.PhysicalName(from.ConfigMapRef.Name, vPod.Namespace) + } } if from.SecretRef != nil && from.SecretRef.Name != "" { envFrom[j].SecretRef.Name = translate.Default.PhysicalName(from.SecretRef.Name, vPod.Namespace) diff --git a/pkg/controllers/syncer/translator/namespaced_translator.go b/pkg/controllers/syncer/translator/namespaced_translator.go index de6d817d4..38dd7a0e5 100644 --- a/pkg/controllers/syncer/translator/namespaced_translator.go +++ b/pkg/controllers/syncer/translator/namespaced_translator.go @@ -34,7 +34,6 @@ func NewNamespacedTranslator(ctx *context.RegisterContext, name string, obj clie type namespacedTranslator struct { name string - nameTranslator translate.PhysicalNamespacedNameTranslator excludedAnnotations []string syncedLabels []string @@ -44,10 +43,6 @@ type namespacedTranslator struct { eventRecorder record.EventRecorder } -func (n *namespacedTranslator) SetNameTranslator(nameTranslator translate.PhysicalNamespacedNameTranslator) { - n.nameTranslator = nameTranslator -} - func (n *namespacedTranslator) EventRecorder() record.EventRecorder { return n.eventRecorder } @@ -103,11 +98,8 @@ func (n *namespacedTranslator) IsManaged(_ context2.Context, pObj client.Object) return translate.Default.IsManaged(pObj), nil } -func (n *namespacedTranslator) VirtualToHost(_ context2.Context, req types.NamespacedName, vObj client.Object) types.NamespacedName { +func (n *namespacedTranslator) VirtualToHost(_ context2.Context, req types.NamespacedName, _ client.Object) types.NamespacedName { name := translate.Default.PhysicalName(req.Name, req.Namespace) - if n.nameTranslator != nil { - name = n.nameTranslator(req, vObj) - } return types.NamespacedName{ Namespace: translate.Default.PhysicalNamespace(req.Namespace), diff --git a/pkg/controllers/syncer/translator/translator.go b/pkg/controllers/syncer/translator/translator.go index 5173ada0a..0db6c0a8d 100644 --- a/pkg/controllers/syncer/translator/translator.go +++ b/pkg/controllers/syncer/translator/translator.go @@ -4,7 +4,6 @@ import ( "context" syncercontext "github.com/loft-sh/vcluster/pkg/controllers/syncer/context" - "github.com/loft-sh/vcluster/pkg/util/translate" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" @@ -56,7 +55,4 @@ type NamespacedTranslator interface { // SyncToHostUpdate updates the given pObj (if not nil) in the target namespace SyncToHostUpdate(ctx *syncercontext.SyncContext, vObj, pObj client.Object) (ctrl.Result, error) - - // SetNameTranslator is a function to override default VirtualToHost name translation - SetNameTranslator(nameTranslator translate.PhysicalNamespacedNameTranslator) }