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

refactor: move resolvers into engine api package (#6162)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-01-31 08:46:38 +01:00 committed by GitHub
parent f93995e812
commit 0237cc5c71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 246 additions and 142 deletions

View file

@ -30,6 +30,7 @@ import (
webhookcontroller "github.com/kyverno/kyverno/pkg/controllers/webhook" webhookcontroller "github.com/kyverno/kyverno/pkg/controllers/webhook"
"github.com/kyverno/kyverno/pkg/cosign" "github.com/kyverno/kyverno/pkg/cosign"
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers" "github.com/kyverno/kyverno/pkg/engine/context/resolvers"
"github.com/kyverno/kyverno/pkg/event" "github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/leaderelection" "github.com/kyverno/kyverno/pkg/leaderelection"
@ -113,7 +114,7 @@ func createNonLeaderControllers(
policyCache policycache.Cache, policyCache policycache.Cache,
eventGenerator event.Interface, eventGenerator event.Interface,
manager openapi.Manager, manager openapi.Manager,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
) ([]internal.Controller, func() error) { ) ([]internal.Controller, func() error) {
policyCacheController := policycachecontroller.NewController( policyCacheController := policycachecontroller.NewController(
dynamicClient, dynamicClient,
@ -170,7 +171,7 @@ func createrLeaderControllers(
eventGenerator event.Interface, eventGenerator event.Interface,
certRenewer tls.CertRenewer, certRenewer tls.CertRenewer,
runtime runtimeutils.Runtime, runtime runtimeutils.Runtime,
configMapResolver resolvers.ConfigmapResolver, configMapResolver engineapi.ConfigmapResolver,
servicePort int32, servicePort int32,
) ([]internal.Controller, func(context.Context) error, error) { ) ([]internal.Controller, func(context.Context) error, error) {
policyCtrl, err := policy.NewPolicyController( policyCtrl, err := policy.NewPolicyController(
@ -353,7 +354,7 @@ func main() {
logger.Error(err, "failed to create client based resolver") logger.Error(err, "failed to create client based resolver")
os.Exit(1) os.Exit(1)
} }
configMapResolver, err := resolvers.NewResolverChain(informerBasedResolver, clientBasedResolver) configMapResolver, err := engineapi.NewNamespacedResourceResolver(informerBasedResolver, clientBasedResolver)
if err != nil { if err != nil {
logger.Error(err, "failed to create config map resolver") logger.Error(err, "failed to create config map resolver")
os.Exit(1) os.Exit(1)

View file

@ -24,6 +24,7 @@ import (
backgroundscancontroller "github.com/kyverno/kyverno/pkg/controllers/report/background" backgroundscancontroller "github.com/kyverno/kyverno/pkg/controllers/report/background"
resourcereportcontroller "github.com/kyverno/kyverno/pkg/controllers/report/resource" resourcereportcontroller "github.com/kyverno/kyverno/pkg/controllers/report/resource"
"github.com/kyverno/kyverno/pkg/cosign" "github.com/kyverno/kyverno/pkg/cosign"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers" "github.com/kyverno/kyverno/pkg/engine/context/resolvers"
"github.com/kyverno/kyverno/pkg/event" "github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/leaderelection" "github.com/kyverno/kyverno/pkg/leaderelection"
@ -75,7 +76,7 @@ func createReportControllers(
metadataFactory metadatainformers.SharedInformerFactory, metadataFactory metadatainformers.SharedInformerFactory,
kubeInformer kubeinformers.SharedInformerFactory, kubeInformer kubeinformers.SharedInformerFactory,
kyvernoInformer kyvernoinformer.SharedInformerFactory, kyvernoInformer kyvernoinformer.SharedInformerFactory,
configMapResolver resolvers.ConfigmapResolver, configMapResolver engineapi.ConfigmapResolver,
backgroundScanInterval time.Duration, backgroundScanInterval time.Duration,
configuration config.Configuration, configuration config.Configuration,
eventGenerator event.Interface, eventGenerator event.Interface,
@ -166,7 +167,7 @@ func createrLeaderControllers(
rclient registryclient.Client, rclient registryclient.Client,
configuration config.Configuration, configuration config.Configuration,
eventGenerator event.Interface, eventGenerator event.Interface,
configMapResolver resolvers.ConfigmapResolver, configMapResolver engineapi.ConfigmapResolver,
backgroundScanInterval time.Duration, backgroundScanInterval time.Duration,
) ([]internal.Controller, func(context.Context) error, error) { ) ([]internal.Controller, func(context.Context) error, error) {
reportControllers, warmup := createReportControllers( reportControllers, warmup := createReportControllers(
@ -271,7 +272,7 @@ func main() {
logger.Error(err, "failed to create client based resolver") logger.Error(err, "failed to create client based resolver")
os.Exit(1) os.Exit(1)
} }
configMapResolver, err := resolvers.NewResolverChain(informerBasedResolver, clientBasedResolver) configMapResolver, err := engineapi.NewNamespacedResourceResolver(informerBasedResolver, clientBasedResolver)
if err != nil { if err != nil {
logger.Error(err, "failed to create config map resolver") logger.Error(err, "failed to create config map resolver")
os.Exit(1) os.Exit(1)

View file

@ -21,6 +21,7 @@ import (
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
policymetricscontroller "github.com/kyverno/kyverno/pkg/controllers/metrics/policy" policymetricscontroller "github.com/kyverno/kyverno/pkg/controllers/metrics/policy"
"github.com/kyverno/kyverno/pkg/cosign" "github.com/kyverno/kyverno/pkg/cosign"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers" "github.com/kyverno/kyverno/pkg/engine/context/resolvers"
"github.com/kyverno/kyverno/pkg/event" "github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/leaderelection" "github.com/kyverno/kyverno/pkg/leaderelection"
@ -71,7 +72,7 @@ func createNonLeaderControllers(
rclient registryclient.Client, rclient registryclient.Client,
configuration config.Configuration, configuration config.Configuration,
eventGenerator event.Interface, eventGenerator event.Interface,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
) []internal.Controller { ) []internal.Controller {
updateRequestController := background.NewController( updateRequestController := background.NewController(
kyvernoClient, kyvernoClient,
@ -98,7 +99,7 @@ func createrLeaderControllers(
configuration config.Configuration, configuration config.Configuration,
metricsConfig metrics.MetricsConfigManager, metricsConfig metrics.MetricsConfigManager,
eventGenerator event.Interface, eventGenerator event.Interface,
configMapResolver resolvers.ConfigmapResolver, configMapResolver engineapi.ConfigmapResolver,
) ([]internal.Controller, error) { ) ([]internal.Controller, error) {
policyCtrl, err := policy.NewPolicyController( policyCtrl, err := policy.NewPolicyController(
kyvernoClient, kyvernoClient,
@ -199,7 +200,7 @@ func main() {
logger.Error(err, "failed to create client based resolver") logger.Error(err, "failed to create client based resolver")
os.Exit(1) os.Exit(1)
} }
configMapResolver, err := resolvers.NewResolverChain(informerBasedResolver, clientBasedResolver) configMapResolver, err := engineapi.NewNamespacedResourceResolver(informerBasedResolver, clientBasedResolver)
if err != nil { if err != nil {
logger.Error(err, "failed to create config map resolver") logger.Error(err, "failed to create config map resolver")
os.Exit(1) os.Exit(1)

View file

@ -10,8 +10,8 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission" admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -21,7 +21,7 @@ func NewBackgroundContext(dclient dclient.Interface, ur *kyvernov1beta1.UpdateRe
policy kyvernov1.PolicyInterface, policy kyvernov1.PolicyInterface,
trigger *unstructured.Unstructured, trigger *unstructured.Unstructured,
cfg config.Configuration, cfg config.Configuration,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
namespaceLabels map[string]string, namespaceLabels map[string]string,
logger logr.Logger, logger logr.Logger,
) (*engine.PolicyContext, bool, error) { ) (*engine.PolicyContext, bool, error) {

View file

@ -23,7 +23,6 @@ import (
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api" engineapi "github.com/kyverno/kyverno/pkg/engine/api"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context" enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
"github.com/kyverno/kyverno/pkg/engine/variables" "github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/event" "github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/registryclient" "github.com/kyverno/kyverno/pkg/registryclient"
@ -53,7 +52,7 @@ type GenerateController struct {
npolicyLister kyvernov1listers.PolicyLister npolicyLister kyvernov1listers.PolicyLister
configuration config.Configuration configuration config.Configuration
informerCacheResolvers resolvers.ConfigmapResolver informerCacheResolvers engineapi.ConfigmapResolver
eventGen event.Interface eventGen event.Interface
log logr.Logger log logr.Logger
@ -70,7 +69,7 @@ func NewGenerateController(
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister, urLister kyvernov1beta1listers.UpdateRequestNamespaceLister,
nsLister corev1listers.NamespaceLister, nsLister corev1listers.NamespaceLister,
dynamicConfig config.Configuration, dynamicConfig config.Configuration,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
eventGen event.Interface, eventGen event.Interface,
log logr.Logger, log logr.Logger,
) *GenerateController { ) *GenerateController {

View file

@ -14,7 +14,6 @@ import (
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api" engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
"github.com/kyverno/kyverno/pkg/event" "github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/registryclient" "github.com/kyverno/kyverno/pkg/registryclient"
"github.com/kyverno/kyverno/pkg/utils" "github.com/kyverno/kyverno/pkg/utils"
@ -37,7 +36,7 @@ type MutateExistingController struct {
npolicyLister kyvernov1listers.PolicyLister npolicyLister kyvernov1listers.PolicyLister
configuration config.Configuration configuration config.Configuration
informerCacheResolvers resolvers.ConfigmapResolver informerCacheResolvers engineapi.ConfigmapResolver
eventGen event.Interface eventGen event.Interface
log logr.Logger log logr.Logger
@ -51,7 +50,7 @@ func NewMutateExistingController(
policyLister kyvernov1listers.ClusterPolicyLister, policyLister kyvernov1listers.ClusterPolicyLister,
npolicyLister kyvernov1listers.PolicyLister, npolicyLister kyvernov1listers.PolicyLister,
dynamicConfig config.Configuration, dynamicConfig config.Configuration,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
eventGen event.Interface, eventGen event.Interface,
log logr.Logger, log logr.Logger,
) *MutateExistingController { ) *MutateExistingController {

View file

@ -18,7 +18,7 @@ import (
kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1" kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers" engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/event" "github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/registryclient" "github.com/kyverno/kyverno/pkg/registryclient"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube" kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
@ -65,7 +65,7 @@ type controller struct {
eventGen event.Interface eventGen event.Interface
configuration config.Configuration configuration config.Configuration
informerCacheResolvers resolvers.ConfigmapResolver informerCacheResolvers engineapi.ConfigmapResolver
} }
// NewController returns an instance of the Generate-Request Controller // NewController returns an instance of the Generate-Request Controller
@ -80,7 +80,7 @@ func NewController(
podInformer corev1informers.PodInformer, podInformer corev1informers.PodInformer,
eventGen event.Interface, eventGen event.Interface,
dynamicConfig config.Configuration, dynamicConfig config.Configuration,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
) Controller { ) Controller {
urLister := urInformer.Lister().UpdateRequests(config.KyvernoNamespace()) urLister := urInformer.Lister().UpdateRequests(config.KyvernoNamespace())
c := controller{ c := controller{

View file

@ -18,7 +18,7 @@ import (
"github.com/kyverno/kyverno/pkg/controllers/report/resource" "github.com/kyverno/kyverno/pkg/controllers/report/resource"
"github.com/kyverno/kyverno/pkg/controllers/report/utils" "github.com/kyverno/kyverno/pkg/controllers/report/utils"
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers" engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/event" "github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/registryclient" "github.com/kyverno/kyverno/pkg/registryclient"
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller" controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
@ -63,7 +63,7 @@ type controller struct {
// cache // cache
metadataCache resource.MetadataCache metadataCache resource.MetadataCache
informerCacheResolvers resolvers.ConfigmapResolver informerCacheResolvers engineapi.ConfigmapResolver
forceDelay time.Duration forceDelay time.Duration
// config // config
@ -81,7 +81,7 @@ func NewController(
nsInformer corev1informers.NamespaceInformer, nsInformer corev1informers.NamespaceInformer,
polexLister engine.PolicyExceptionLister, polexLister engine.PolicyExceptionLister,
metadataCache resource.MetadataCache, metadataCache resource.MetadataCache,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
forceDelay time.Duration, forceDelay time.Duration,
config config.Configuration, config config.Configuration,
eventGen event.Interface, eventGen event.Interface,

View file

@ -10,7 +10,6 @@ import (
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api" engineapi "github.com/kyverno/kyverno/pkg/engine/api"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context" enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
"github.com/kyverno/kyverno/pkg/registryclient" "github.com/kyverno/kyverno/pkg/registryclient"
"go.uber.org/multierr" "go.uber.org/multierr"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -20,7 +19,7 @@ type scanner struct {
logger logr.Logger logger logr.Logger
client dclient.Interface client dclient.Interface
rclient registryclient.Client rclient registryclient.Client
informerCacheResolvers resolvers.ConfigmapResolver informerCacheResolvers engineapi.ConfigmapResolver
polexLister engine.PolicyExceptionLister polexLister engine.PolicyExceptionLister
excludeGroupRole []string excludeGroupRole []string
config config.Configuration config config.Configuration
@ -39,7 +38,7 @@ func NewScanner(
logger logr.Logger, logger logr.Logger,
client dclient.Interface, client dclient.Interface,
rclient registryclient.Client, rclient registryclient.Client,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
polexLister engine.PolicyExceptionLister, polexLister engine.PolicyExceptionLister,
config config.Configuration, config config.Configuration,
excludeGroupRole ...string, excludeGroupRole ...string,

View file

@ -0,0 +1,52 @@
package api
import (
"context"
"errors"
corev1 "k8s.io/api/core/v1"
)
// NamespacedResourceResolver is an abstract interface used to resolve namespaced resources
// Any implementation might exist, cache based, file based, client based etc...
type NamespacedResourceResolver[T any] interface {
// Get is used to resolve a resource given a namespace and name
Get(
ctx context.Context,
namespace string,
name string,
) (T, error)
}
// ConfigmapResolver is an abstract interface used to resolve configmaps
type ConfigmapResolver = NamespacedResourceResolver[*corev1.ConfigMap]
// namespacedResourceResolverChain represents a chain of NamespacedResourceResolver
type namespacedResourceResolverChain[T any] []NamespacedResourceResolver[T]
// NewNamespacedResourceResolver creates a NamespacedResourceResolver from a NamespacedResourceResolver chain
// It will try to resolve resources by iterating over individual resolvers until one finds the requested resource
func NewNamespacedResourceResolver[T any](resolvers ...NamespacedResourceResolver[T]) (NamespacedResourceResolver[T], error) {
if len(resolvers) == 0 {
return nil, errors.New("no resolvers")
}
for _, resolver := range resolvers {
if resolver == nil {
return nil, errors.New("at least one resolver is nil")
}
}
return namespacedResourceResolverChain[T](resolvers), nil
}
func (chain namespacedResourceResolverChain[T]) Get(ctx context.Context, namespace, name string) (T, error) {
var lastErr error
for _, resolver := range chain {
r, err := resolver.Get(ctx, namespace, name)
if err == nil {
return r, nil
}
lastErr = err
}
var notFound T
return notFound, lastErr
}

View file

@ -0,0 +1,135 @@
package api
import (
"context"
"errors"
"reflect"
"testing"
corev1 "k8s.io/api/core/v1"
)
type dummyResolver struct {
err error
cm *corev1.ConfigMap
}
func (c dummyResolver) Get(context.Context, string, string) (*corev1.ConfigMap, error) {
return c.cm, c.err
}
func TestNewNamespacedResourceResolver(t *testing.T) {
type args struct {
resolvers []ConfigmapResolver
}
tests := []struct {
name string
args args
want ConfigmapResolver
wantErr bool
}{{
name: "nil shoud return an error",
wantErr: true,
}, {
name: "empty list shoud return an error",
args: args{[]ConfigmapResolver{}},
wantErr: true,
}, {
name: "one nil in the list shoud return an error",
args: args{[]ConfigmapResolver{dummyResolver{}, nil}},
wantErr: true,
}, {
name: "no nil",
args: args{[]ConfigmapResolver{dummyResolver{}, dummyResolver{}, dummyResolver{}}},
want: namespacedResourceResolverChain[*corev1.ConfigMap]{dummyResolver{}, dummyResolver{}, dummyResolver{}},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewNamespacedResourceResolver(tt.args.resolvers...)
if (err != nil) != tt.wantErr {
t.Errorf("NewResolverChain() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewResolverChain() = %v, want %v", got, tt.want)
}
})
}
}
func Test_namespacedResourceResolverChain_Get(t *testing.T) {
type fields struct {
resolvers []ConfigmapResolver
}
type args struct {
namespace string
name string
}
tests := []struct {
name string
fields fields
args args
wantErr error
wantCm *corev1.ConfigMap
}{{
fields: fields{
resolvers: []ConfigmapResolver{
dummyResolver{},
dummyResolver{},
dummyResolver{},
},
},
}, {
fields: fields{
resolvers: []ConfigmapResolver{
dummyResolver{
err: errors.New("1"),
},
dummyResolver{
err: errors.New("2"),
},
dummyResolver{
err: errors.New("3"),
},
},
},
wantErr: errors.New("3"),
}, {
fields: fields{
resolvers: []ConfigmapResolver{
dummyResolver{
err: errors.New("1"),
},
dummyResolver{},
dummyResolver{
err: errors.New("3"),
},
},
},
}, {
fields: fields{
resolvers: []ConfigmapResolver{
dummyResolver{
err: errors.New("1"),
},
dummyResolver{
err: errors.New("2"),
},
dummyResolver{},
},
},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resolver, _ := NewNamespacedResourceResolver(tt.fields.resolvers...)
got, err := resolver.Get(context.TODO(), tt.args.namespace, tt.args.name)
if !reflect.DeepEqual(err, tt.wantErr) {
t.Errorf("ConfigmapResolver.Get() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.wantCm) {
t.Errorf("ConfigmapResolver.Get() = %v, want %v", got, tt.wantCm)
}
})
}
}

View file

@ -1,7 +1,5 @@
package resolvers package resolvers
const ( const (
TEST_NAMESPACE = "default"
TEST_CONFIGMAP = "myconfigmap"
LabelCacheKey = "cache.kyverno.io/enabled" LabelCacheKey = "cache.kyverno.io/enabled"
) )

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"github.com/kyverno/kyverno/pkg/engine/api"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
@ -14,7 +15,7 @@ type informerBasedResolver struct {
lister corev1listers.ConfigMapLister lister corev1listers.ConfigMapLister
} }
func NewInformerBasedResolver(lister corev1listers.ConfigMapLister) (ConfigmapResolver, error) { func NewInformerBasedResolver(lister corev1listers.ConfigMapLister) (api.ConfigmapResolver, error) {
if lister == nil { if lister == nil {
return nil, errors.New("lister must not be nil") return nil, errors.New("lister must not be nil")
} }
@ -29,7 +30,7 @@ type clientBasedResolver struct {
kubeClient kubernetes.Interface kubeClient kubernetes.Interface
} }
func NewClientBasedResolver(client kubernetes.Interface) (ConfigmapResolver, error) { func NewClientBasedResolver(client kubernetes.Interface) (api.ConfigmapResolver, error) {
if client == nil { if client == nil {
return nil, errors.New("client must not be nil") return nil, errors.New("client must not be nil")
} }
@ -39,32 +40,3 @@ func NewClientBasedResolver(client kubernetes.Interface) (ConfigmapResolver, err
func (c *clientBasedResolver) Get(ctx context.Context, namespace, name string) (*corev1.ConfigMap, error) { func (c *clientBasedResolver) Get(ctx context.Context, namespace, name string) (*corev1.ConfigMap, error) {
return c.kubeClient.CoreV1().ConfigMaps(namespace).Get(ctx, name, metav1.GetOptions{}) return c.kubeClient.CoreV1().ConfigMaps(namespace).Get(ctx, name, metav1.GetOptions{})
} }
type resolverChain []ConfigmapResolver
func NewResolverChain(resolvers ...ConfigmapResolver) (ConfigmapResolver, error) {
if len(resolvers) == 0 {
return nil, errors.New("no resolvers")
}
for _, resolver := range resolvers {
if resolver == nil {
return nil, errors.New("at least one resolver is nil")
}
}
return resolverChain(resolvers), nil
}
func (chain resolverChain) Get(ctx context.Context, namespace, name string) (*corev1.ConfigMap, error) {
// if CM is not found in informer cache, error will be stored in
// lastErr variable and resolver chain will try to get CM using
// Kubernetes client
var lastErr error
for _, resolver := range chain {
cm, err := resolver.Get(ctx, namespace, name)
if err == nil {
return cm, nil
}
lastErr = err
}
return nil, lastErr
}

View file

@ -6,6 +6,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/kyverno/kyverno/pkg/engine/api"
"gotest.tools/assert" "gotest.tools/assert"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -15,6 +16,11 @@ import (
corev1listers "k8s.io/client-go/listers/core/v1" corev1listers "k8s.io/client-go/listers/core/v1"
) )
const (
namespace = "default"
name = "myconfigmap"
)
func newEmptyFakeClient() *kubefake.Clientset { func newEmptyFakeClient() *kubefake.Clientset {
return kubefake.NewSimpleClientset() return kubefake.NewSimpleClientset()
} }
@ -22,15 +28,15 @@ func newEmptyFakeClient() *kubefake.Clientset {
func createConfigMaps(ctx context.Context, client *kubefake.Clientset, addLabel bool) error { func createConfigMaps(ctx context.Context, client *kubefake.Clientset, addLabel bool) error {
cm := &corev1.ConfigMap{ cm := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: TEST_CONFIGMAP, Name: name,
Namespace: TEST_NAMESPACE, Namespace: namespace,
}, },
Data: map[string]string{"configmapkey": "key1"}, Data: map[string]string{"configmapkey": "key1"},
} }
if addLabel { if addLabel {
cm.ObjectMeta.Labels = map[string]string{LabelCacheKey: "true"} cm.ObjectMeta.Labels = map[string]string{LabelCacheKey: "true"}
} }
_, err := client.CoreV1().ConfigMaps(TEST_NAMESPACE).Create( _, err := client.CoreV1().ConfigMaps(namespace).Create(
ctx, cm, metav1.CreateOptions{}) ctx, cm, metav1.CreateOptions{})
return err return err
} }
@ -57,7 +63,7 @@ func Test_InformerCacheSuccess(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
informer.Start(make(<-chan struct{})) informer.Start(make(<-chan struct{}))
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
_, err = informerResolver.Get(ctx, TEST_NAMESPACE, TEST_CONFIGMAP) _, err = informerResolver.Get(ctx, namespace, name)
assert.NilError(t, err, "informer didn't have expected configmap") assert.NilError(t, err, "informer didn't have expected configmap")
} }
@ -71,7 +77,7 @@ func Test_InformerCacheFailure(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
informer.Start(make(<-chan struct{})) informer.Start(make(<-chan struct{}))
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
_, err = resolver.Get(ctx, TEST_NAMESPACE, TEST_CONFIGMAP) _, err = resolver.Get(ctx, namespace, name)
assert.Equal(t, err.Error(), "configmap \"myconfigmap\" not found") assert.Equal(t, err.Error(), "configmap \"myconfigmap\" not found")
} }
@ -82,7 +88,7 @@ func Test_ClientBasedResolver(t *testing.T) {
assert.NilError(t, err, "error while creating configmap") assert.NilError(t, err, "error while creating configmap")
resolver, err := NewClientBasedResolver(client) resolver, err := NewClientBasedResolver(client)
assert.NilError(t, err) assert.NilError(t, err)
_, err = resolver.Get(ctx, TEST_NAMESPACE, TEST_CONFIGMAP) _, err = resolver.Get(ctx, namespace, name)
assert.NilError(t, err, "error while getting configmap from client") assert.NilError(t, err, "error while getting configmap from client")
} }
@ -94,12 +100,12 @@ func Test_ResolverChainWithExistingConfigMap(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
clientBasedResolver, err := NewClientBasedResolver(client) clientBasedResolver, err := NewClientBasedResolver(client)
assert.NilError(t, err) assert.NilError(t, err)
resolvers, err := NewResolverChain(informerBasedResolver, clientBasedResolver) resolvers, err := api.NewNamespacedResourceResolver(informerBasedResolver, clientBasedResolver)
assert.NilError(t, err) assert.NilError(t, err)
ctx := context.TODO() ctx := context.TODO()
err = createConfigMaps(ctx, client, true) err = createConfigMaps(ctx, client, true)
assert.NilError(t, err, "error while creating configmap") assert.NilError(t, err, "error while creating configmap")
_, err = resolvers.Get(ctx, TEST_NAMESPACE, TEST_CONFIGMAP) _, err = resolvers.Get(ctx, namespace, name)
assert.NilError(t, err, "error while getting configmap") assert.NilError(t, err, "error while getting configmap")
} }
@ -111,10 +117,10 @@ func Test_ResolverChainWithNonExistingConfigMap(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
clientBasedResolver, err := NewClientBasedResolver(client) clientBasedResolver, err := NewClientBasedResolver(client)
assert.NilError(t, err) assert.NilError(t, err)
resolvers, err := NewResolverChain(informerBasedResolver, clientBasedResolver) resolvers, err := api.NewNamespacedResourceResolver(informerBasedResolver, clientBasedResolver)
assert.NilError(t, err) assert.NilError(t, err)
ctx := context.TODO() ctx := context.TODO()
_, err = resolvers.Get(ctx, TEST_NAMESPACE, TEST_CONFIGMAP) _, err = resolvers.Get(ctx, namespace, name)
assert.Error(t, err, "configmaps \"myconfigmap\" not found") assert.Error(t, err, "configmaps \"myconfigmap\" not found")
} }
@ -128,7 +134,7 @@ func TestNewInformerBasedResolver(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want ConfigmapResolver want api.ConfigmapResolver
wantErr bool wantErr bool
}{{ }{{
name: "nil shoud return an error", name: "nil shoud return an error",
@ -160,7 +166,7 @@ func TestNewClientBasedResolver(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
args args args args
want ConfigmapResolver want api.ConfigmapResolver
wantErr bool wantErr bool
}{{ }{{
name: "nil shoud return an error", name: "nil shoud return an error",
@ -183,48 +189,3 @@ func TestNewClientBasedResolver(t *testing.T) {
}) })
} }
} }
type dummyResolver struct{}
func (c dummyResolver) Get(context.Context, string, string) (*corev1.ConfigMap, error) {
return nil, nil
}
func TestNewResolverChain(t *testing.T) {
type args struct {
resolvers []ConfigmapResolver
}
tests := []struct {
name string
args args
want ConfigmapResolver
wantErr bool
}{{
name: "nil shoud return an error",
wantErr: true,
}, {
name: "empty list shoud return an error",
args: args{[]ConfigmapResolver{}},
wantErr: true,
}, {
name: "one nil in the list shoud return an error",
args: args{[]ConfigmapResolver{dummyResolver{}, nil}},
wantErr: true,
}, {
name: "no nil",
args: args{[]ConfigmapResolver{dummyResolver{}, dummyResolver{}, dummyResolver{}}},
want: resolverChain{dummyResolver{}, dummyResolver{}, dummyResolver{}},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewResolverChain(tt.args.resolvers...)
if (err != nil) != tt.wantErr {
t.Errorf("NewResolverChain() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewResolverChain() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -1,13 +0,0 @@
package resolvers
import (
"context"
corev1 "k8s.io/api/core/v1"
)
type NamespacedResourceResolver[T any] interface {
Get(context.Context, string, string) (T, error)
}
type ConfigmapResolver = NamespacedResourceResolver[*corev1.ConfigMap]

View file

@ -6,8 +6,8 @@ import (
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1" kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
"github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/api"
enginectx "github.com/kyverno/kyverno/pkg/engine/context" enginectx "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission" admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
"github.com/pkg/errors" "github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1" admissionv1 "k8s.io/api/admission/v1"
@ -71,7 +71,7 @@ type PolicyContext struct {
admissionOperation bool admissionOperation bool
// informerCacheResolvers - used to get resources from informer cache // informerCacheResolvers - used to get resources from informer cache
informerCacheResolvers resolvers.ConfigmapResolver informerCacheResolvers api.ConfigmapResolver
// subresource is the subresource being requested, if any (for example, "status" or "scale") // subresource is the subresource being requested, if any (for example, "status" or "scale")
subresource string subresource string
@ -205,7 +205,7 @@ func (c *PolicyContext) WithAdmissionOperation(admissionOperation bool) *PolicyC
return copy return copy
} }
func (c *PolicyContext) WithInformerCacheResolver(informerCacheResolver resolvers.ConfigmapResolver) *PolicyContext { func (c *PolicyContext) WithInformerCacheResolver(informerCacheResolver api.ConfigmapResolver) *PolicyContext {
copy := c.Copy() copy := c.Copy()
copy.informerCacheResolvers = informerCacheResolver copy.informerCacheResolvers = informerCacheResolver
return copy return copy
@ -253,7 +253,7 @@ func NewPolicyContextFromAdmissionRequest(
admissionInfo kyvernov1beta1.RequestInfo, admissionInfo kyvernov1beta1.RequestInfo,
configuration config.Configuration, configuration config.Configuration,
client dclient.Interface, client dclient.Interface,
informerCacheResolver resolvers.ConfigmapResolver, informerCacheResolver api.ConfigmapResolver,
polexLister PolicyExceptionLister, polexLister PolicyExceptionLister,
) (*PolicyContext, error) { ) (*PolicyContext, error) {
ctx, err := newVariablesContext(request, &admissionInfo) ctx, err := newVariablesContext(request, &admissionInfo)

View file

@ -23,7 +23,6 @@ import (
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api" engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
"github.com/kyverno/kyverno/pkg/event" "github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/metrics" "github.com/kyverno/kyverno/pkg/metrics"
"github.com/kyverno/kyverno/pkg/registryclient" "github.com/kyverno/kyverno/pkg/registryclient"
@ -82,7 +81,7 @@ type PolicyController struct {
// nsLister can list/get namespaces from the shared informer's store // nsLister can list/get namespaces from the shared informer's store
nsLister corev1listers.NamespaceLister nsLister corev1listers.NamespaceLister
informerCacheResolvers resolvers.ConfigmapResolver informerCacheResolvers engineapi.ConfigmapResolver
informersSynced []cache.InformerSynced informersSynced []cache.InformerSynced
@ -107,7 +106,7 @@ func NewPolicyController(
configHandler config.Configuration, configHandler config.Configuration,
eventGen event.Interface, eventGen event.Interface,
namespaces corev1informers.NamespaceInformer, namespaces corev1informers.NamespaceInformer,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
log logr.Logger, log logr.Logger,
reconcilePeriod time.Duration, reconcilePeriod time.Duration,
metricsConfig metrics.MetricsConfigManager, metricsConfig metrics.MetricsConfigManager,

View file

@ -13,8 +13,8 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
enginectx "github.com/kyverno/kyverno/pkg/engine/context" enginectx "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
"github.com/kyverno/kyverno/pkg/event" "github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/metrics" "github.com/kyverno/kyverno/pkg/metrics"
"github.com/kyverno/kyverno/pkg/openapi" "github.com/kyverno/kyverno/pkg/openapi"
@ -72,7 +72,7 @@ func NewHandlers(
configuration config.Configuration, configuration config.Configuration,
metricsConfig metrics.MetricsConfigManager, metricsConfig metrics.MetricsConfigManager,
pCache policycache.Cache, pCache policycache.Cache,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
nsLister corev1listers.NamespaceLister, nsLister corev1listers.NamespaceLister,
rbLister rbacv1listers.RoleBindingLister, rbLister rbacv1listers.RoleBindingLister,
crbLister rbacv1listers.ClusterRoleBindingLister, crbLister rbacv1listers.ClusterRoleBindingLister,

View file

@ -5,7 +5,7 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers" engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/userinfo" "github.com/kyverno/kyverno/pkg/userinfo"
"github.com/pkg/errors" "github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1" admissionv1 "k8s.io/api/admission/v1"
@ -21,7 +21,7 @@ type policyContextBuilder struct {
client dclient.Interface client dclient.Interface
rbLister rbacv1listers.RoleBindingLister rbLister rbacv1listers.RoleBindingLister
crbLister rbacv1listers.ClusterRoleBindingLister crbLister rbacv1listers.ClusterRoleBindingLister
informerCacheResolvers resolvers.ConfigmapResolver informerCacheResolvers engineapi.ConfigmapResolver
polexLister engine.PolicyExceptionLister polexLister engine.PolicyExceptionLister
} }
@ -30,7 +30,7 @@ func NewPolicyContextBuilder(
client dclient.Interface, client dclient.Interface,
rbLister rbacv1listers.RoleBindingLister, rbLister rbacv1listers.RoleBindingLister,
crbLister rbacv1listers.ClusterRoleBindingLister, crbLister rbacv1listers.ClusterRoleBindingLister,
informerCacheResolvers resolvers.ConfigmapResolver, informerCacheResolvers engineapi.ConfigmapResolver,
polexLister engine.PolicyExceptionLister, polexLister engine.PolicyExceptionLister,
) PolicyContextBuilder { ) PolicyContextBuilder {
return &policyContextBuilder{ return &policyContextBuilder{