mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 18:38:40 +00:00
inital commit: redesign the policyengine to make it stateless
This commit is contained in:
parent
6d83aa6b9e
commit
e4366c55be
8 changed files with 129 additions and 178 deletions
4
main.go
4
main.go
|
@ -11,7 +11,6 @@ import (
|
|||
|
||||
policyclientset "github.com/nirmata/kube-policy/pkg/client/clientset/versioned"
|
||||
informers "github.com/nirmata/kube-policy/pkg/client/informers/externalversions"
|
||||
policyengine "github.com/nirmata/kube-policy/pkg/policyengine"
|
||||
policyviolation "github.com/nirmata/kube-policy/pkg/policyviolation"
|
||||
|
||||
event "github.com/nirmata/kube-policy/pkg/event"
|
||||
|
@ -46,11 +45,9 @@ func main() {
|
|||
|
||||
eventController := event.NewEventController(kubeclient, policyInformer.Lister(), nil)
|
||||
violationBuilder := policyviolation.NewPolicyViolationBuilder(kubeclient, policyInformer.Lister(), policyClientset, eventController, nil)
|
||||
policyEngine := policyengine.NewPolicyEngine(kubeclient, nil)
|
||||
|
||||
policyController := policycontroller.NewPolicyController(policyClientset,
|
||||
policyInformer,
|
||||
policyEngine,
|
||||
violationBuilder,
|
||||
eventController,
|
||||
nil,
|
||||
|
@ -59,7 +56,6 @@ func main() {
|
|||
mutationWebhook, err := webhooks.CreateMutationWebhook(clientConfig,
|
||||
kubeclient,
|
||||
policyInformer.Lister(),
|
||||
violationBuilder,
|
||||
eventController,
|
||||
nil)
|
||||
if err != nil {
|
||||
|
|
85
pkg/policyengine/generate.go
Normal file
85
pkg/policyengine/generate.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
package policyengine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
"github.com/nirmata/kube-policy/pkg/policyengine/mutation"
|
||||
)
|
||||
|
||||
// Generate should be called to process generate rules on the resource
|
||||
func Generate(logger *log.Logger, policy types.Policy, rawResource []byte) ([]GenerateReturnData, error) {
|
||||
patchingSets := mutation.GetPolicyPatchingSets(policy)
|
||||
generatedList := []GenerateReturnData{}
|
||||
for ruleIdx, rule := range policy.Spec.Rules {
|
||||
err := rule.Validate()
|
||||
if err != nil {
|
||||
logger.Printf("Invalid rule detected: #%d in policy %s, err: %v\n", ruleIdx, policy.ObjectMeta.Name, err)
|
||||
continue
|
||||
}
|
||||
if ok, err := mutation.IsRuleApplicableToResource(rawResource, rule.Resource); !ok {
|
||||
logger.Printf("Rule %d of policy %s is not applicable to the request", ruleIdx, policy.Name)
|
||||
return nil, err
|
||||
}
|
||||
resourceKind := mutation.ParseKindFromObject(rawResource)
|
||||
|
||||
// configMapGenerator and secretGenerator can be applied only to namespaces
|
||||
if resourceKind == "Namespace" {
|
||||
generatedData, err := applyRuleGenerators(rawResource, rule)
|
||||
if err != nil && patchingSets == mutation.PatchingSetsStopOnError {
|
||||
return nil, fmt.Errorf("Failed to apply generators from rule #%d: %s", ruleIdx, err)
|
||||
}
|
||||
generatedList = append(generatedList, generatedData...)
|
||||
}
|
||||
}
|
||||
return generatedList, nil
|
||||
}
|
||||
|
||||
// Applies "configMapGenerator" and "secretGenerator" described in PolicyRule
|
||||
func applyRuleGenerators(rawResource []byte, rule types.PolicyRule) ([]GenerateReturnData, error) {
|
||||
returnData := []GenerateReturnData{}
|
||||
namespaceName := mutation.ParseNameFromObject(rawResource)
|
||||
var generator *types.PolicyConfigGenerator
|
||||
// Apply config map generator rule
|
||||
generator, err := applyConfigGenerator(rule.ConfigMapGenerator, namespaceName, "ConfigMap")
|
||||
if err != nil {
|
||||
return returnData, err
|
||||
}
|
||||
returnData = append(returnData, GenerateReturnData{namespaceName, "ConfigMap", *generator})
|
||||
// Apply secrets generator rule
|
||||
generator, err = applyConfigGenerator(rule.SecretGenerator, namespaceName, "Secret")
|
||||
if err != nil {
|
||||
return returnData, err
|
||||
}
|
||||
returnData = append(returnData, GenerateReturnData{namespaceName, "Secret", *generator})
|
||||
|
||||
return returnData, nil
|
||||
}
|
||||
|
||||
// Creates resourceKind (ConfigMap or Secret) with parameters specified in generator in cluster specified in request.
|
||||
func applyConfigGenerator(generator *types.PolicyConfigGenerator, namespace string, configKind string) (*types.PolicyConfigGenerator, error) {
|
||||
if generator == nil {
|
||||
return nil, nil
|
||||
}
|
||||
err := generator.Validate()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Generator for '%s' is invalid: %s", configKind, err)
|
||||
}
|
||||
switch configKind {
|
||||
case "ConfigMap":
|
||||
return generator, nil
|
||||
// err = kubeClient.GenerateConfigMap(*generator, namespace)
|
||||
case "Secret":
|
||||
return generator, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported config Kind '%s'", configKind)
|
||||
}
|
||||
}
|
||||
|
||||
//GenerateReturnData holds the generator details
|
||||
type GenerateReturnData struct {
|
||||
namespace string
|
||||
configKind string
|
||||
generator types.PolicyConfigGenerator
|
||||
}
|
|
@ -1,30 +1,31 @@
|
|||
package policyengine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
"github.com/nirmata/kube-policy/pkg/policyengine/mutation"
|
||||
)
|
||||
|
||||
func (p *policyEngine) ProcessMutation(policy types.Policy, rawResource []byte) ([]mutation.PatchBytes, error) {
|
||||
// Mutation should be claed to process the mutation rules on the resource
|
||||
//TODO return []event.Info
|
||||
func Mutation(logger *log.Logger, policy types.Policy, rawResource []byte) ([]mutation.PatchBytes, error) {
|
||||
patchingSets := mutation.GetPolicyPatchingSets(policy)
|
||||
var policyPatches []mutation.PatchBytes
|
||||
|
||||
for ruleIdx, rule := range policy.Spec.Rules {
|
||||
err := rule.Validate()
|
||||
if err != nil {
|
||||
p.logger.Printf("Invalid rule detected: #%s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err)
|
||||
logger.Printf("Invalid rule detected: #%s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if ok, err := mutation.IsRuleApplicableToResource(rawResource, rule.Resource); !ok {
|
||||
p.logger.Printf("Rule %d of policy %s is not applicable to the request", ruleIdx, policy.Name)
|
||||
logger.Printf("Rule %d of policy %s is not applicable to the request", ruleIdx, policy.Name)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = p.applyRuleGenerators(rawResource, rule)
|
||||
if err != nil && patchingSets == mutation.PatchingSetsStopOnError {
|
||||
return nil, fmt.Errorf("Failed to apply generators from rule #%s: %v", rule.Name, err)
|
||||
}
|
||||
|
@ -36,10 +37,10 @@ func (p *policyEngine) ProcessMutation(policy types.Policy, rawResource []byte)
|
|||
|
||||
if rulePatchesProcessed != nil {
|
||||
policyPatches = append(policyPatches, rulePatchesProcessed...)
|
||||
p.logger.Printf("Rule %d: prepared %d patches", ruleIdx, len(rulePatchesProcessed))
|
||||
logger.Printf("Rule %d: prepared %d patches", ruleIdx, len(rulePatchesProcessed))
|
||||
// TODO: add PolicyApplied events per rule for policy and resource
|
||||
} else {
|
||||
p.logger.Printf("Rule %d: no patches prepared", ruleIdx)
|
||||
logger.Printf("Rule %d: no patches prepared", ruleIdx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,47 +51,3 @@ func (p *policyEngine) ProcessMutation(policy types.Policy, rawResource []byte)
|
|||
|
||||
return policyPatches, nil
|
||||
}
|
||||
|
||||
// Applies "configMapGenerator" and "secretGenerator" described in PolicyRule
|
||||
func (p *policyEngine) applyRuleGenerators(rawResource []byte, rule types.PolicyRule) error {
|
||||
kind := mutation.ParseKindFromObject(rawResource)
|
||||
|
||||
// configMapGenerator and secretGenerator can be applied only to namespaces
|
||||
if kind == "Namespace" {
|
||||
namespaceName := mutation.ParseNameFromObject(rawResource)
|
||||
|
||||
err := p.applyConfigGenerator(rule.ConfigMapGenerator, namespaceName, "ConfigMap")
|
||||
if err == nil {
|
||||
err = p.applyConfigGenerator(rule.SecretGenerator, namespaceName, "Secret")
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates resourceKind (ConfigMap or Secret) with parameters specified in generator in cluster specified in request.
|
||||
func (p *policyEngine) applyConfigGenerator(generator *types.PolicyConfigGenerator, namespace string, configKind string) error {
|
||||
if generator == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := generator.Validate()
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("Generator for '%s' is invalid: %s", configKind, err))
|
||||
}
|
||||
|
||||
switch configKind {
|
||||
case "ConfigMap":
|
||||
err = p.kubeClient.GenerateConfigMap(*generator, namespace)
|
||||
case "Secret":
|
||||
err = p.kubeClient.GenerateSecret(*generator, namespace)
|
||||
default:
|
||||
err = errors.New(fmt.Sprintf("Unsupported config Kind '%s'", configKind))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("Unable to apply generator for %s '%s/%s' : %s", configKind, namespace, generator.Name, err))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,103 +1,17 @@
|
|||
package policyengine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
kubeClient "github.com/nirmata/kube-policy/kubeclient"
|
||||
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
event "github.com/nirmata/kube-policy/pkg/event"
|
||||
"github.com/nirmata/kube-policy/pkg/policyengine/mutation"
|
||||
policyviolation "github.com/nirmata/kube-policy/pkg/policyviolation"
|
||||
"github.com/nirmata/kube-policy/pkg/event"
|
||||
"github.com/nirmata/kube-policy/pkg/policyviolation"
|
||||
)
|
||||
|
||||
type PolicyEngine interface {
|
||||
// ProcessMutation should be called from admission contoller
|
||||
// when there is an creation / update of the resource
|
||||
// ProcessMutation(policy types.Policy, rawResource []byte) (patchBytes []byte, events []Events, err error)
|
||||
ProcessMutation(policy types.Policy, rawResource []byte) ([]mutation.PatchBytes, error)
|
||||
// As the logic to process the policies in stateless, we do not need to define struct and implement behaviors for it
|
||||
// Instead we expose them as standalone functions passing the logger and the required atrributes
|
||||
// The each function returns the changes that need to be applied on the resource
|
||||
// the caller is responsible to apply the changes to the resource
|
||||
|
||||
// ProcessValidation should be called from admission contoller
|
||||
// when there is an creation / update of the resource
|
||||
ProcessValidation(policy types.Policy, rawResource []byte)
|
||||
|
||||
// ProcessExisting should be called from policy controller
|
||||
// when there is an create / update of the policy
|
||||
// we should process the policy on matched resources, generate violations accordingly
|
||||
ProcessExisting(policy types.Policy, rawResource []byte) ([]policyviolation.Info, []event.Info, error)
|
||||
}
|
||||
|
||||
type policyEngine struct {
|
||||
kubeClient *kubeClient.KubeClient
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewPolicyEngine(kubeClient *kubeClient.KubeClient, logger *log.Logger) PolicyEngine {
|
||||
return &policyEngine{
|
||||
kubeClient: kubeClient,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *policyEngine) ProcessExisting(policy types.Policy, rawResource []byte) ([]policyviolation.Info, []event.Info, error) {
|
||||
var violations []policyviolation.Info
|
||||
var events []event.Info
|
||||
|
||||
patchingSets := mutation.GetPolicyPatchingSets(policy)
|
||||
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
err := rule.Validate()
|
||||
if err != nil {
|
||||
p.logger.Printf("Invalid rule detected: #%s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if ok, err := mutation.IsRuleApplicableToResource(rawResource, rule.Resource); !ok {
|
||||
p.logger.Printf("Rule %s of policy %s is not applicable to the request", rule.Name, policy.Name)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
violation, eventInfos, err := p.processRuleOnResource(policy.Name, rule, rawResource, patchingSets)
|
||||
if err != nil {
|
||||
p.logger.Printf("Failed to process rule %s, err: %v\n", rule.Name, err)
|
||||
continue
|
||||
}
|
||||
// } else {
|
||||
// policyPatches = append(policyPatches, processedPatches...)
|
||||
// }
|
||||
violations = append(violations, violation)
|
||||
events = append(events, eventInfos...)
|
||||
}
|
||||
return violations, events, nil
|
||||
}
|
||||
|
||||
func (p *policyEngine) processRuleOnResource(policyName string, rule types.PolicyRule, rawResource []byte, patchingSets mutation.PatchingSets) (
|
||||
policyviolation.Info, []event.Info, error) {
|
||||
|
||||
var violationInfo policyviolation.Info
|
||||
var eventInfos []event.Info
|
||||
|
||||
resourceKind := mutation.ParseKindFromObject(rawResource)
|
||||
resourceName := mutation.ParseNameFromObject(rawResource)
|
||||
resourceNamespace := mutation.ParseNamespaceFromObject(rawResource)
|
||||
|
||||
rulePatchesProcessed, err := mutation.ProcessPatches(rule.Patches, nil, patchingSets)
|
||||
if err != nil {
|
||||
return violationInfo, eventInfos, fmt.Errorf("Failed to process patches from rule %s: %v", rule.Name, err)
|
||||
}
|
||||
|
||||
if rulePatchesProcessed != nil {
|
||||
log.Printf("Rule %s: prepared %d patches", rule.Name, len(rulePatchesProcessed))
|
||||
|
||||
violationInfo = policyviolation.NewViolation(policyName, resourceKind, resourceNamespace+"/"+resourceName, rule.Name)
|
||||
// add a violation to queue
|
||||
|
||||
// add an event to policy
|
||||
//TODO: event msg
|
||||
eventInfos = append(eventInfos, event.NewEvent("Policy", policyName, event.PolicyViolation, event.FResourcePolcy))
|
||||
// add an event to resource
|
||||
eventInfos = append(eventInfos, event.NewEvent(resourceKind, resourceNamespace+"/"+resourceName, event.PolicyViolation, event.FResourcePolcy))
|
||||
}
|
||||
|
||||
return violationInfo, eventInfos, nil
|
||||
//TODO wrap the generate, mutation & validation functions for the existing resources
|
||||
func ProcessExisting(policy types.Policy, rawResource []byte) ([]policyviolation.Info, []event.Info, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
package policyengine
|
||||
|
||||
import types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
import (
|
||||
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
"github.com/nirmata/kube-policy/pkg/event"
|
||||
"github.com/nirmata/kube-policy/pkg/policyviolation"
|
||||
)
|
||||
|
||||
func (p *policyEngine) ProcessValidation(policy types.Policy, rawResource []byte) {}
|
||||
// Validation should be called to process validation rules on the resource
|
||||
//TODO: validate should return a bool to specify if the validation was succesful or not
|
||||
func Validation(policy types.Policy, rawResource []byte) (bool, []policyviolation.Info, []event.Info) {
|
||||
return true, nil, nil
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
infomertypes "github.com/nirmata/kube-policy/pkg/client/informers/externalversions/policy/v1alpha1"
|
||||
lister "github.com/nirmata/kube-policy/pkg/client/listers/policy/v1alpha1"
|
||||
event "github.com/nirmata/kube-policy/pkg/event"
|
||||
policyengine "github.com/nirmata/kube-policy/pkg/policyengine"
|
||||
|
||||
policyviolation "github.com/nirmata/kube-policy/pkg/policyviolation"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -27,7 +27,6 @@ type PolicyController struct {
|
|||
policyLister lister.PolicyLister
|
||||
policyInterface policyclientset.Interface
|
||||
policySynced cache.InformerSynced
|
||||
policyEngine policyengine.PolicyEngine
|
||||
violationBuilder policyviolation.Generator
|
||||
eventBuilder event.Generator
|
||||
logger *log.Logger
|
||||
|
@ -37,7 +36,6 @@ type PolicyController struct {
|
|||
// NewPolicyController from cmd args
|
||||
func NewPolicyController(policyInterface policyclientset.Interface,
|
||||
policyInformer infomertypes.PolicyInformer,
|
||||
policyEngine policyengine.PolicyEngine,
|
||||
violationBuilder policyviolation.Generator,
|
||||
eventController event.Generator,
|
||||
logger *log.Logger,
|
||||
|
@ -48,7 +46,6 @@ func NewPolicyController(policyInterface policyclientset.Interface,
|
|||
policyLister: policyInformer.Lister(),
|
||||
policyInterface: policyInterface,
|
||||
policySynced: policyInformer.Informer().HasSynced,
|
||||
policyEngine: policyEngine,
|
||||
violationBuilder: violationBuilder,
|
||||
eventBuilder: eventController,
|
||||
logger: logger,
|
||||
|
|
|
@ -5,9 +5,10 @@ import (
|
|||
"fmt"
|
||||
|
||||
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
event "github.com/nirmata/kube-policy/pkg/event"
|
||||
"github.com/nirmata/kube-policy/pkg/event"
|
||||
"github.com/nirmata/kube-policy/pkg/policyengine"
|
||||
"github.com/nirmata/kube-policy/pkg/policyengine/mutation"
|
||||
policyviolation "github.com/nirmata/kube-policy/pkg/policyviolation"
|
||||
"github.com/nirmata/kube-policy/pkg/policyviolation"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
|
@ -57,7 +58,7 @@ func (pc *PolicyController) processPolicy(policy types.Policy) (
|
|||
continue
|
||||
}
|
||||
|
||||
violation, eventInfos, err := pc.policyEngine.ProcessExisting(policy, rawResource)
|
||||
violation, eventInfos, err := policyengine.ProcessExisting(policy, rawResource)
|
||||
if err != nil {
|
||||
pc.logger.Printf("Failed to process rule %s, err: %v\n", rule.Name, err)
|
||||
continue
|
||||
|
|
|
@ -11,9 +11,8 @@ import (
|
|||
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||
policylister "github.com/nirmata/kube-policy/pkg/client/listers/policy/v1alpha1"
|
||||
event "github.com/nirmata/kube-policy/pkg/event"
|
||||
policyengine "github.com/nirmata/kube-policy/pkg/policyengine"
|
||||
"github.com/nirmata/kube-policy/pkg/policyengine"
|
||||
mutation "github.com/nirmata/kube-policy/pkg/policyengine/mutation"
|
||||
policyviolation "github.com/nirmata/kube-policy/pkg/policyviolation"
|
||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -25,13 +24,11 @@ import (
|
|||
// MutationWebhook is a data type that represents
|
||||
// business logic for resource mutation
|
||||
type MutationWebhook struct {
|
||||
kubeclient *kubeclient.KubeClient
|
||||
policyEngine policyengine.PolicyEngine
|
||||
policyLister policylister.PolicyLister
|
||||
registration *MutationWebhookRegistration
|
||||
violationBuilder policyviolation.Generator
|
||||
eventBuilder event.Generator
|
||||
logger *log.Logger
|
||||
kubeclient *kubeclient.KubeClient
|
||||
policyLister policylister.PolicyLister
|
||||
registration *MutationWebhookRegistration
|
||||
eventBuilder event.Generator
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// Registers mutation webhook in cluster and creates object for this webhook
|
||||
|
@ -39,7 +36,6 @@ func CreateMutationWebhook(
|
|||
clientConfig *rest.Config,
|
||||
kubeclient *kubeclient.KubeClient,
|
||||
policyLister policylister.PolicyLister,
|
||||
violationBuilder policyviolation.Generator,
|
||||
eventController event.Generator,
|
||||
logger *log.Logger) (*MutationWebhook, error) {
|
||||
if clientConfig == nil || kubeclient == nil {
|
||||
|
@ -59,16 +55,13 @@ func CreateMutationWebhook(
|
|||
if logger == nil {
|
||||
logger = log.New(os.Stdout, "Mutation WebHook: ", log.LstdFlags|log.Lshortfile)
|
||||
}
|
||||
policyengine := policyengine.NewPolicyEngine(kubeclient, logger)
|
||||
|
||||
return &MutationWebhook{
|
||||
kubeclient: kubeclient,
|
||||
policyEngine: policyengine,
|
||||
policyLister: policyLister,
|
||||
registration: registration,
|
||||
violationBuilder: violationBuilder,
|
||||
eventBuilder: eventController,
|
||||
logger: logger,
|
||||
kubeclient: kubeclient,
|
||||
policyLister: policyLister,
|
||||
registration: registration,
|
||||
eventBuilder: eventController,
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -141,7 +134,7 @@ func (mw *MutationWebhook) Mutate(request *v1beta1.AdmissionRequest) *v1beta1.Ad
|
|||
// May return nil patches if it is not necessary to create patches for requested object.
|
||||
// Returns error ONLY in case when creation of resource should be denied.
|
||||
func (mw *MutationWebhook) applyPolicyRules(request *v1beta1.AdmissionRequest, policy types.Policy) ([]mutation.PatchBytes, error) {
|
||||
return mw.policyEngine.ProcessMutation(policy, request.Object.Raw)
|
||||
return policyengine.Mutation(mw.logger, policy, request.Object.Raw)
|
||||
}
|
||||
|
||||
// kind is the type of object being manipulated, e.g. request.Kind.kind
|
||||
|
|
Loading…
Add table
Reference in a new issue