1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

Bug Fix: Extends match / exclude to use apiGroup and apiVersion (#1218) (#1656)

* Extends match / exclude to use apiGroup and apiVersion

Signed-off-by: vyankatesh <vyankatesh@neualto.com>

* fix gvk issue

Signed-off-by: vyankatesh <vyankatesh@neualto.com>

Co-authored-by: vyankatesh <vyankatesh@neualto.com>
This commit is contained in:
Vyankatesh Kudtarkar 2021-03-05 06:15:52 +05:30 committed by GitHub
parent adb381705f
commit 9e831ec959
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 73 additions and 46 deletions

View file

@ -2,6 +2,7 @@ package common
import (
"encoding/json"
"strings"
"github.com/go-logr/logr"
enginutils "github.com/kyverno/kyverno/pkg/engine/utils"
@ -64,3 +65,15 @@ func GetNamespaceLabels(namespaceObj *v1.Namespace, logger logr.Logger) map[stri
}
return namespaceUnstructured.GetLabels()
}
// GetKindFromGVK - get kind and APIVersion from GVK
func GetKindFromGVK(str string) (apiVersion string, kind string) {
if strings.Count(str, "/") == 0 {
return "", str
}
splitString := strings.Split(str, "/")
if strings.Count(str, "/") == 1 {
return splitString[0], splitString[1]
}
return splitString[0] + "/" + splitString[1], splitString[2]
}

View file

@ -21,14 +21,15 @@ func filterRules(policyContext *PolicyContext) *response.EngineResponse {
kind := policyContext.NewResource.GetKind()
name := policyContext.NewResource.GetName()
namespace := policyContext.NewResource.GetNamespace()
apiVersion := policyContext.NewResource.GetAPIVersion()
resp := &response.EngineResponse{
PolicyResponse: response.PolicyResponse{
Policy: policyContext.Policy.Name,
Resource: response.ResourceSpec{
Kind: kind,
Name: name,
Namespace: namespace,
Kind: kind,
Name: name,
Namespace: namespace,
APIVersion: apiVersion,
},
},
}

View file

@ -28,10 +28,21 @@ type EngineStats struct {
RulesAppliedCount int
}
func checkKind(kinds []string, resourceKind string) bool {
func checkKind(kinds []string, resource unstructured.Unstructured) bool {
for _, kind := range kinds {
if resourceKind == kind {
return true
SplitGVK := strings.Split(kind, "/")
if len(SplitGVK) == 1 {
if resource.GetKind() == kind {
return true
}
} else if len(SplitGVK) == 2 {
if resource.GroupVersionKind().Kind == SplitGVK[1] && resource.GroupVersionKind().Version == SplitGVK[0] {
return true
}
} else {
if resource.GroupVersionKind().Group == SplitGVK[0] && resource.GroupVersionKind().Kind == SplitGVK[2] && (resource.GroupVersionKind().Version == SplitGVK[1] || resource.GroupVersionKind().Version == "*") {
return true
}
}
}
@ -113,7 +124,7 @@ func doesResourceMatchConditionBlock(conditionBlock kyverno.ResourceDescription,
var errs []error
if len(conditionBlock.Kinds) > 0 {
if !checkKind(conditionBlock.Kinds, resource.GetKind()) {
if !checkKind(conditionBlock.Kinds, resource) {
errs = append(errs, fmt.Errorf("kind does not match %v", conditionBlock.Kinds))
}
}

View file

@ -218,7 +218,7 @@ func (gen *Generator) syncHandler(key Info) error {
func (gen *Generator) getResource(key Info) (obj *unstructured.Unstructured, err error) {
lister, ok := gen.resCache.GetGVRCache(key.Kind)
if !ok {
if lister, err = gen.resCache.CreateResourceInformer(key.Kind); err != nil {
if lister, err = gen.resCache.CreateGVKInformer(key.Kind); err != nil {
return nil, err
}
}

View file

@ -51,15 +51,14 @@ func (pc *PolicyController) processExistingResources(policy *kyverno.ClusterPoli
}
}
func (pc *PolicyController) registerResource(kind string) (err error) {
genericCache, ok := pc.resCache.GetGVRCache(kind)
func (pc *PolicyController) registerResource(gvk string) (err error) {
genericCache, ok := pc.resCache.GetGVRCache(gvk)
if !ok {
if genericCache, err = pc.resCache.CreateResourceInformer(kind); err != nil {
return fmt.Errorf("failed to create informer for %s: %v", kind, err)
if genericCache, err = pc.resCache.CreateGVKInformer(gvk); err != nil {
return fmt.Errorf("failed to create informer for %s: %v", gvk, err)
}
}
pc.rm.RegisterScope(kind, genericCache.IsNamespaced())
pc.rm.RegisterScope(gvk, genericCache.IsNamespaced())
return nil
}

View file

@ -12,7 +12,7 @@ import (
// ResourceCache - allows the creation, deletion and saving the resource informers as a cache
type ResourceCache interface {
CreateInformers(resources ...string) []error
CreateResourceInformer(resource string) (GenericCache, error)
CreateGVKInformer(kind string) (GenericCache, error)
StopResourceInformer(resource string)
GetGVRCache(resource string) (GenericCache, bool)
}

View file

@ -2,45 +2,21 @@ package resourcecache
import (
"fmt"
"github.com/kyverno/kyverno/pkg/common"
)
// CreateInformers ...
func (resc *resourceCache) CreateInformers(resources ...string) []error {
var errs []error
for _, resource := range resources {
if _, err := resc.CreateResourceInformer(resource); err != nil {
if _, err := resc.CreateGVKInformer(resource); err != nil {
errs = append(errs, fmt.Errorf("failed to create informer for %s: %v", resource, err))
}
}
return errs
}
// CreateResourceInformer creates informer for the given resource
func (resc *resourceCache) CreateResourceInformer(resource string) (GenericCache, error) {
gc, ok := resc.GetGVRCache(resource)
if ok {
return gc, nil
}
apiResource, gvr, err := resc.dclient.DiscoveryClient.FindResource("", resource)
if err != nil {
return nil, fmt.Errorf("cannot find API resource %s", resource)
}
stopCh := make(chan struct{})
genInformer := resc.dinformer.ForResource(gvr)
gvrIface := NewGVRCache(gvr, apiResource.Namespaced, stopCh, genInformer)
resc.gvrCache.Set(resource, gvrIface)
resc.dinformer.Start(stopCh)
if synced := resc.dinformer.WaitForCacheSync(stopCh); !synced[gvr] {
return nil, fmt.Errorf("informer for %s hasn't synced", gvr)
}
return gvrIface, nil
}
// StopResourceInformer - delete the given resource information from ResourceCache and stop watching for the given resource
func (resc *resourceCache) StopResourceInformer(resource string) {
res, ok := resc.GetGVRCache(resource)
@ -61,3 +37,29 @@ func (resc *resourceCache) GetGVRCache(resource string) (GenericCache, bool) {
return nil, false
}
// CreateGVKInformer creates informer for the given gvk
func (resc *resourceCache) CreateGVKInformer(gvk string) (GenericCache, error) {
gc, ok := resc.GetGVRCache(gvk)
if ok {
return gc, nil
}
gv, k := common.GetKindFromGVK(gvk)
apiResource, gvr, err := resc.dclient.DiscoveryClient.FindResource(gv, k)
if err != nil {
return nil, fmt.Errorf("cannot find API resource %s", gvk)
}
stopCh := make(chan struct{})
genInformer := resc.dinformer.ForResource(gvr)
gvrIface := NewGVRCache(gvr, apiResource.Namespaced, stopCh, genInformer)
resc.gvrCache.Set(gvk, gvrIface)
resc.dinformer.Start(stopCh)
if synced := resc.dinformer.WaitForCacheSync(stopCh); !synced[gvr] {
return nil, fmt.Errorf("informer for %s hasn't synced", gvr)
}
return gvrIface, nil
}

View file

@ -310,9 +310,10 @@ func transform(userRequestInfo kyverno.RequestInfo, er *response.EngineResponse)
gr := kyverno.GenerateRequestSpec{
Policy: er.PolicyResponse.Policy,
Resource: kyverno.ResourceSpec{
Kind: er.PolicyResponse.Resource.Kind,
Namespace: er.PolicyResponse.Resource.Namespace,
Name: er.PolicyResponse.Resource.Name,
Kind: er.PolicyResponse.Resource.Kind,
Namespace: er.PolicyResponse.Resource.Namespace,
Name: er.PolicyResponse.Resource.Name,
APIVersion: er.PolicyResponse.Resource.APIVersion,
},
Context: kyverno.GenerateRequestContext{
UserRequestInfo: userRequestInfo,