Skip to content

Commit

Permalink
Bug Fix: Extends match / exclude to use apiGroup and apiVersion (#1218)…
Browse files Browse the repository at this point in the history
… (#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>
  • Loading branch information
vyankyGH and vyankd committed Mar 5, 2021
1 parent adb3817 commit 9e831ec
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 46 deletions.
13 changes: 13 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package common

import (
"encoding/json"
"strings"

"github.com/go-logr/logr"
enginutils "github.com/kyverno/kyverno/pkg/engine/utils"
Expand Down Expand Up @@ -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]
}
9 changes: 5 additions & 4 deletions pkg/engine/generation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
},
}
Expand Down
19 changes: 15 additions & 4 deletions pkg/engine/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}

Expand Down Expand Up @@ -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))
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/event/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
11 changes: 5 additions & 6 deletions pkg/policy/existing.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/resourcecache/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
56 changes: 29 additions & 27 deletions pkg/resourcecache/resourcecache.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
}
7 changes: 4 additions & 3 deletions pkg/webhooks/generation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 9e831ec

Please sign in to comment.