diff --git a/pkg/mappings/resources/services.go b/pkg/mappings/resources/services.go index 16be9bb39..f75734cc0 100644 --- a/pkg/mappings/resources/services.go +++ b/pkg/mappings/resources/services.go @@ -1,29 +1,76 @@ package resources import ( + "fmt" + "github.com/loft-sh/vcluster/pkg/mappings/generic" "github.com/loft-sh/vcluster/pkg/syncer/synccontext" "github.com/loft-sh/vcluster/pkg/util/translate" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" ) func CreateServiceMapper(ctx *synccontext.RegisterContext) (synccontext.Mapper, error) { - mapper, err := generic.NewMapper(ctx, &corev1.Service{}, translate.Default.HostName) + mapper, err := generic.NewMapperWithoutRecorder(ctx, &corev1.Service{}, func(ctx *synccontext.SyncContext, vName, vNamespace string, _ client.Object) types.NamespacedName { + return translate.Default.HostName(ctx, vName, vNamespace) + }) if err != nil { return nil, err } - return &servicesMapper{ + return generic.WithRecorder(&servicesMapper{ Mapper: mapper, - }, nil + }), nil } type servicesMapper struct { synccontext.Mapper } +func (s *servicesMapper) Migrate(ctx *synccontext.RegisterContext, _ synccontext.Mapper) error { + vObj := synccontext.Object{ + GroupVersionKind: s.GroupVersionKind(), + NamespacedName: types.NamespacedName{ + Namespace: "default", + Name: "kubernetes", + }, + } + expectedHostName := types.NamespacedName{ + Name: translate.VClusterName, + Namespace: ctx.CurrentNamespace, + } + + // check if there is an existing mapping already + existingHostName, ok := ctx.Mappings.Store().VirtualToHostName(ctx, vObj) + if ok && existingHostName.String() != expectedHostName.String() { + klog.FromContext(ctx).Info("Fix default/kubernetes mapping", "before", existingHostName, "now", expectedHostName) + + // delete existing mapping & references + existingMapping := vObj.WithHostName(existingHostName) + err := ctx.Mappings.Store().DeleteMapping(ctx, existingMapping) + if err != nil { + return err + } + for _, reference := range ctx.Mappings.Store().ReferencesTo(ctx, vObj) { + err = ctx.Mappings.Store().DeleteReferenceAndSave(ctx, existingMapping, reference) + if err != nil { + return fmt.Errorf("delete reference: %w", err) + } + } + + // add new mapping + expectedMapping := vObj.WithHostName(expectedHostName) + err = ctx.Mappings.Store().AddReferenceAndSave(ctx, expectedMapping, expectedMapping) + if err != nil { + return fmt.Errorf("add mapping: %w", err) + } + } + + return nil +} + func (s *servicesMapper) VirtualToHost(ctx *synccontext.SyncContext, req types.NamespacedName, vObj client.Object) types.NamespacedName { if req.Name == "kubernetes" && req.Namespace == "default" { return types.NamespacedName{ @@ -43,5 +90,10 @@ func (s *servicesMapper) HostToVirtual(ctx *synccontext.SyncContext, req types.N } } - return s.Mapper.HostToVirtual(ctx, req, pObj) + namespaceName := s.Mapper.HostToVirtual(ctx, req, pObj) + if namespaceName.Name == "kubernetes" && req.Namespace == "default" { + return types.NamespacedName{} + } + + return namespaceName } diff --git a/pkg/syncer/synccontext/mapper.go b/pkg/syncer/synccontext/mapper.go index 473e83008..84904e335 100644 --- a/pkg/syncer/synccontext/mapper.go +++ b/pkg/syncer/synccontext/mapper.go @@ -103,6 +103,22 @@ type Object struct { types.NamespacedName } +func (o Object) WithVirtualName(vName types.NamespacedName) NameMapping { + return NameMapping{ + GroupVersionKind: o.GroupVersionKind, + VirtualName: vName, + HostName: o.NamespacedName, + } +} + +func (o Object) WithHostName(pName types.NamespacedName) NameMapping { + return NameMapping{ + GroupVersionKind: o.GroupVersionKind, + VirtualName: o.NamespacedName, + HostName: pName, + } +} + func (o Object) Equals(other Object) bool { return o.String() == other.String() }