From 24fb6b89812ac86622a536dba861729ed5a20b74 Mon Sep 17 00:00:00 2001 From: Alexander Zielenski Date: Thu, 26 Jan 2023 12:14:14 -0800 Subject: [PATCH] use transformer to set gvk back --- .../validatingadmissionpolicy/controller.go | 29 ------------- .../controller_reconcile.go | 41 +++++++++++++++---- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller.go index 65e46137cbf..795dbad5b9c 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller.go @@ -27,7 +27,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/matching" - k8sscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/api/admissionregistration/v1alpha1" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -294,34 +293,6 @@ func (c *celAdmissionController) Validate( } } - // Ensure param is populated with its GVK for consistency - // (CRD dynamic informer always returns objects with kind/apiversion, - // but native types do not include populated TypeMeta. - if param != nil { - if param.GetObjectKind().GroupVersionKind().Empty() { - // Very unfortunate. Unfortunately object is shared and cannot - // modify GVK async - param = param.DeepCopyObject() - - // https://github.com/kubernetes/client-go/issues/413#issue-324586398 - gvks, _, err := k8sscheme.Scheme.ObjectKinds(param) - if err != nil { - return fmt.Errorf("missing apiVersion or kind and cannot assign it; %w", err) - } - - for _, gvk := range gvks { - if len(gvk.Kind) == 0 { - continue - } - if len(gvk.Version) == 0 || gvk.Version == runtime.APIVersionInternal { - continue - } - param.GetObjectKind().SetGroupVersionKind(gvk) - break - } - } - } - decisions, err := bindingInfo.validator.Validate(a, o, param, matchKind) if err != nil { // runtime error. Apply failure policy diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go index 9a376507a77..2952640eb3e 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go @@ -34,6 +34,7 @@ import ( "k8s.io/client-go/dynamic/dynamicinformer" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" + k8sscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/cache" ) @@ -243,7 +244,7 @@ func (c *policyController) reconcilePolicyDefinition(namespace, name string, def } else { instanceContext, instanceCancel := context.WithCancel(c.context) - var informer informers.GenericInformer + var informer cache.SharedIndexInformer // Informer Factory is optional if c.client != nil { @@ -255,14 +256,41 @@ func (c *policyController) reconcilePolicyDefinition(namespace, name string, def dynamicFactory := informers.NewSharedInformerFactory(c.client, 10*time.Minute) // Look for a typed informer. If it does not exist - informer, err = dynamicFactory.ForResource(paramsGVR.Resource) + genericInformer, err := dynamicFactory.ForResource(paramsGVR.Resource) // Ignore error. We fallback to dynamic informer if there is no // typed informer if err != nil { informer = nil } else { - dynamicFactory.Start(instanceContext.Done()) + informer = genericInformer.Informer() + + // Set transformer on the informer to workaround inconsistency + // where typed objects have TypeMeta wiped out but dynamic + // objects keep kind/apiVersion fields + informer.SetTransform(func(i interface{}) (interface{}, error) { + // Ensure param is populated with its GVK for consistency + // (CRD dynamic informer always returns objects with kind/apiversion, + // but native types do not include populated TypeMeta. + if param := i.(runtime.Object); param != nil { + if param.GetObjectKind().GroupVersionKind().Empty() { + // https://github.com/kubernetes/client-go/issues/413#issue-324586398 + gvks, _, _ := k8sscheme.Scheme.ObjectKinds(param) + for _, gvk := range gvks { + if len(gvk.Kind) == 0 { + continue + } + if len(gvk.Version) == 0 || gvk.Version == runtime.APIVersionInternal { + continue + } + param.GetObjectKind().SetGroupVersionKind(gvk) + break + } + } + } + + return i, nil + }) } } @@ -280,13 +308,11 @@ func (c *policyController) reconcilePolicyDefinition(namespace, name string, def 10*time.Minute, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, nil, - ) - - go informer.Informer().Run(instanceContext.Done()) + ).Informer() } controller := generic.NewController( - generic.NewInformer[runtime.Object](informer.Informer()), + generic.NewInformer[runtime.Object](informer), c.reconcileParams, generic.ControllerOptions{ Workers: 1, @@ -301,6 +327,7 @@ func (c *policyController) reconcilePolicyDefinition(namespace, name string, def } go controller.Run(instanceContext) + go informer.Run(instanceContext.Done()) } return nil