use transformer to set gvk back

This commit is contained in:
Alexander Zielenski 2023-01-26 12:14:14 -08:00
parent 65513eac3a
commit 24fb6b8981
2 changed files with 34 additions and 36 deletions

View File

@ -27,7 +27,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/matching" "k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/matching"
k8sscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/api/admissionregistration/v1alpha1" "k8s.io/api/admissionregistration/v1alpha1"
k8serrors "k8s.io/apimachinery/pkg/api/errors" 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) decisions, err := bindingInfo.validator.Validate(a, o, param, matchKind)
if err != nil { if err != nil {
// runtime error. Apply failure policy // runtime error. Apply failure policy

View File

@ -34,6 +34,7 @@ import (
"k8s.io/client-go/dynamic/dynamicinformer" "k8s.io/client-go/dynamic/dynamicinformer"
"k8s.io/client-go/informers" "k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
k8sscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
) )
@ -243,7 +244,7 @@ func (c *policyController) reconcilePolicyDefinition(namespace, name string, def
} else { } else {
instanceContext, instanceCancel := context.WithCancel(c.context) instanceContext, instanceCancel := context.WithCancel(c.context)
var informer informers.GenericInformer var informer cache.SharedIndexInformer
// Informer Factory is optional // Informer Factory is optional
if c.client != nil { if c.client != nil {
@ -255,14 +256,41 @@ func (c *policyController) reconcilePolicyDefinition(namespace, name string, def
dynamicFactory := informers.NewSharedInformerFactory(c.client, 10*time.Minute) dynamicFactory := informers.NewSharedInformerFactory(c.client, 10*time.Minute)
// Look for a typed informer. If it does not exist // 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 // Ignore error. We fallback to dynamic informer if there is no
// typed informer // typed informer
if err != nil { if err != nil {
informer = nil informer = nil
} else { } 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, 10*time.Minute,
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
nil, nil,
) ).Informer()
go informer.Informer().Run(instanceContext.Done())
} }
controller := generic.NewController( controller := generic.NewController(
generic.NewInformer[runtime.Object](informer.Informer()), generic.NewInformer[runtime.Object](informer),
c.reconcileParams, c.reconcileParams,
generic.ControllerOptions{ generic.ControllerOptions{
Workers: 1, Workers: 1,
@ -301,6 +327,7 @@ func (c *policyController) reconcilePolicyDefinition(namespace, name string, def
} }
go controller.Run(instanceContext) go controller.Run(instanceContext)
go informer.Run(instanceContext.Done())
} }
return nil return nil