diff --git a/pkg/controllers/resources/ingresses/syncer.go b/pkg/controllers/resources/ingresses/syncer.go index 15c18c108..95c143f94 100644 --- a/pkg/controllers/resources/ingresses/syncer.go +++ b/pkg/controllers/resources/ingresses/syncer.go @@ -3,6 +3,7 @@ package ingresses import ( "fmt" + "github.com/loft-sh/vcluster/pkg/controllers/resources/services" "github.com/loft-sh/vcluster/pkg/mappings" "github.com/loft-sh/vcluster/pkg/patcher" "github.com/loft-sh/vcluster/pkg/pro" @@ -31,12 +32,17 @@ func NewSyncer(ctx *synccontext.RegisterContext) (syncertypes.Object, error) { return &ingressSyncer{ GenericTranslator: translator.NewGenericTranslator(ctx, "ingress", &networkingv1.Ingress{}, mapper), Importer: pro.NewImporter(mapper), + + // exclude "field.cattle.io/publicEndpoints" annotation used by Rancher, similar to service syncer + excludedAnnotations: []string{services.RancherPublicEndpointsAnnotation}, }, nil } type ingressSyncer struct { syncertypes.GenericTranslator syncertypes.Importer + + excludedAnnotations []string } var _ syncertypes.OptionsProvider = &ingressSyncer{} @@ -103,7 +109,7 @@ func (s *ingressSyncer) SyncToVirtual(ctx *synccontext.SyncContext, event *syncc return patcher.DeleteHostObject(ctx, event.Host, event.VirtualOld, "virtual object was deleted") } - vIngress := translate.VirtualMetadata(event.Host, s.HostToVirtual(ctx, types.NamespacedName{Name: event.Host.Name, Namespace: event.Host.Namespace}, event.Host)) + vIngress := translate.VirtualMetadata(event.Host, s.HostToVirtual(ctx, types.NamespacedName{Name: event.Host.Name, Namespace: event.Host.Namespace}, event.Host), s.excludedAnnotations...) err := pro.ApplyPatchesVirtualObject(ctx, nil, vIngress, event.Host, ctx.Config.Sync.ToHost.Ingresses.Patches, false) if err != nil { return ctrl.Result{}, err diff --git a/pkg/controllers/resources/ingresses/syncer_test.go b/pkg/controllers/resources/ingresses/syncer_test.go index 3e760f3f0..b5458d7af 100644 --- a/pkg/controllers/resources/ingresses/syncer_test.go +++ b/pkg/controllers/resources/ingresses/syncer_test.go @@ -446,6 +446,83 @@ func TestSync(t *testing.T) { err = syncCtx.PhysicalClient.Get(syncCtx, types.NamespacedName{Name: createdIngress.Name, Namespace: createdIngress.Namespace}, pIngress) assert.NilError(t, err) + _, err = syncer.(*ingressSyncer).Sync(syncCtx, synccontext.NewSyncEventWithOld(pIngress, pIngress, baseIngress.DeepCopy(), vIngress)) + assert.NilError(t, err) + }, + }, + { + Name: "Exclude Rancher managed annotations from syncing", + InitialVirtualState: []runtime.Object{ + &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: baseIngress.Name, + Namespace: baseIngress.Namespace, + Labels: baseIngress.Labels, + Annotations: map[string]string{ + "nginx.ingress.kubernetes.io/auth-secret": "my-secret", + "nginx.ingress.kubernetes.io/auth-tls-secret": baseIngress.Namespace + "/my-secret", + "field.cattle.io/publicEndpoints": `[{"addresses":["192.168.0.10"],"port":80,"protocol":"HTTP","serviceName":"default:nginx","ingressName":"default:test-ingress","hostname":"my-ingress-endpoint.com","path":"/","allNodes":false}]`, + }, + }, + }, + }, + InitialPhysicalState: []runtime.Object{ + &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: createdIngress.Name, + Namespace: createdIngress.Namespace, + Labels: createdIngress.Labels, + }, + }, + }, + ExpectedVirtualState: map[schema.GroupVersionKind][]runtime.Object{ + networkingv1.SchemeGroupVersion.WithKind("Ingress"): { + &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: baseIngress.Name, + Namespace: baseIngress.Namespace, + Labels: baseIngress.Labels, + Annotations: map[string]string{ + "nginx.ingress.kubernetes.io/auth-secret": "my-secret", + "nginx.ingress.kubernetes.io/auth-tls-secret": baseIngress.Namespace + "/my-secret", + "field.cattle.io/publicEndpoints": `[{"addresses":["192.168.0.10"],"port":80,"protocol":"HTTP","serviceName":"default:nginx","ingressName":"default:test-ingress","hostname":"my-ingress-endpoint.com","path":"/","allNodes":false}]`, + }, + }, + }, + }, + }, + ExpectedPhysicalState: map[schema.GroupVersionKind][]runtime.Object{ + networkingv1.SchemeGroupVersion.WithKind("Ingress"): { + &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: createdIngress.Name, + Namespace: createdIngress.Namespace, + Labels: createdIngress.Labels, + Annotations: map[string]string{ + "nginx.ingress.kubernetes.io/auth-secret": translate.Default.HostName(nil, "my-secret", baseIngress.Namespace).Name, + "nginx.ingress.kubernetes.io/auth-tls-secret": createdIngress.Namespace + "/" + translate.Default.HostName(nil, "my-secret", baseIngress.Namespace).Name, + "vcluster.loft.sh/object-name": baseIngress.Name, + "vcluster.loft.sh/object-namespace": baseIngress.Namespace, + translate.UIDAnnotation: "", + translate.KindAnnotation: networkingv1.SchemeGroupVersion.WithKind("Ingress").String(), + translate.HostNamespaceAnnotation: createdIngress.Namespace, + translate.HostNameAnnotation: createdIngress.Name, + }, + }, + }, + }, + }, + Sync: func(registerContext *synccontext.RegisterContext) { + syncCtx, syncer := syncertesting.FakeStartSyncer(t, registerContext, NewSyncer) + + vIngress := &networkingv1.Ingress{} + err := syncCtx.VirtualClient.Get(syncCtx, types.NamespacedName{Name: baseIngress.Name, Namespace: baseIngress.Namespace}, vIngress) + assert.NilError(t, err) + + pIngress := &networkingv1.Ingress{} + err = syncCtx.PhysicalClient.Get(syncCtx, types.NamespacedName{Name: createdIngress.Name, Namespace: createdIngress.Namespace}, pIngress) + assert.NilError(t, err) + _, err = syncer.(*ingressSyncer).Sync(syncCtx, synccontext.NewSyncEventWithOld(pIngress, pIngress, baseIngress.DeepCopy(), vIngress)) assert.NilError(t, err) }, diff --git a/pkg/controllers/resources/ingresses/translate.go b/pkg/controllers/resources/ingresses/translate.go index 8f59f0d8b..4c96490b2 100644 --- a/pkg/controllers/resources/ingresses/translate.go +++ b/pkg/controllers/resources/ingresses/translate.go @@ -7,6 +7,7 @@ import ( "github.com/loft-sh/vcluster/pkg/mappings" "github.com/loft-sh/vcluster/pkg/mappings/resources" "github.com/loft-sh/vcluster/pkg/syncer/synccontext" + "github.com/loft-sh/vcluster/pkg/util/stringutil" "github.com/loft-sh/vcluster/pkg/util/translate" networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/types" @@ -21,7 +22,7 @@ const ( ) func (s *ingressSyncer) translate(ctx *synccontext.SyncContext, vIngress *networkingv1.Ingress) (*networkingv1.Ingress, error) { - newIngress := translate.HostMetadata(vIngress, s.VirtualToHost(ctx, types.NamespacedName{Name: vIngress.Name, Namespace: vIngress.Namespace}, vIngress)) + newIngress := translate.HostMetadata(vIngress, s.VirtualToHost(ctx, types.NamespacedName{Name: vIngress.Name, Namespace: vIngress.Namespace}, vIngress), s.excludedAnnotations...) newIngress.Spec = *translateSpec(ctx, vIngress.Namespace, &vIngress.Spec) newIngress.Annotations = updateAnnotations(ctx, newIngress.Annotations, vIngress.Namespace) return newIngress, nil @@ -42,6 +43,9 @@ func (s *ingressSyncer) translateUpdate(ctx *synccontext.SyncContext, event *syn if strings.HasPrefix(key, AlbActionsAnnotation) || strings.HasPrefix(key, AlbConditionAnnotation) { return "", nil } + if stringutil.Contains(s.excludedAnnotations, key) { + return "", nil + } return key, value }, func(key string, value interface{}) (string, interface{}) { @@ -50,6 +54,10 @@ func (s *ingressSyncer) translateUpdate(ctx *synccontext.SyncContext, event *syn if !ok { return key, value } + // we ignore excluded annotations + if stringutil.Contains(s.excludedAnnotations, key) { + return "", nil + } // translate the annotation translatedAnnotations := updateAnnotations(ctx, map[string]string{ diff --git a/pkg/controllers/resources/services/syncer.go b/pkg/controllers/resources/services/syncer.go index bc449532a..0bebcd9a8 100644 --- a/pkg/controllers/resources/services/syncer.go +++ b/pkg/controllers/resources/services/syncer.go @@ -23,7 +23,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -var ServiceBlockDeletion = "vcluster.loft.sh/block-deletion" +var ( + ServiceBlockDeletion = "vcluster.loft.sh/block-deletion" + RancherPublicEndpointsAnnotation = "field.cattle.io/publicEndpoints" +) func New(ctx *synccontext.RegisterContext) (syncertypes.Object, error) { mapper, err := ctx.Mappings.ByGVK(mappings.Services()) @@ -39,7 +42,7 @@ func New(ctx *synccontext.RegisterContext) (syncertypes.Object, error) { Importer: pro.NewImporter(mapper), excludedAnnotations: []string{ - "field.cattle.io/publicEndpoints", + RancherPublicEndpointsAnnotation, }, serviceName: ctx.Config.WorkloadService,