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

Reconcile Generate request on policy update (#1096)

* policy report crd added

* added namespaced rule

* remove extra field from crd

* revert crd change

* remove policy report chnages

* remove policy report chnages

* remove policy report chnages

* remove policy report chnages

* added logic for gr

* revert changes

* fixed generate rules

* fixed generate rules

* fixed generate rules

* fixed generate rules

* remove extra logs

* remove extra logs

* fixed e2e test

* remove extra logs

* crd issue resolved

* added check for sync

* add labels update

* add label update

* added permission to role

* roles added to helm

* roles added to helm
This commit is contained in:
Yuvraj 2020-09-04 03:04:23 +05:30 committed by GitHub
parent 154b1c1eb9
commit b7524467a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 313 additions and 231 deletions

View file

@ -131,6 +131,7 @@ rules:
- limitranges
- clusterroles
- rolebindings
- namespaces
- clusterrolebindings
{{- range .Values.generatecontrollerExtraResources }}
- {{ . }}
@ -139,6 +140,7 @@ rules:
- create
- update
- delete
- list
- get
# dynamic watches on trigger resources for generate rules
# re-evaluate the policy if the resource is updated

View file

@ -194,6 +194,7 @@ func main() {
pInformer.Kyverno().V1().Policies(),
pInformer.Kyverno().V1().ClusterPolicyViolations(),
pInformer.Kyverno().V1().PolicyViolations(),
pInformer.Kyverno().V1().GenerateRequests(),
configData,
eventGenerator,
pvgen,

View file

@ -14,7 +14,7 @@ spec:
plural: clusterpolicies
singular: clusterpolicy
shortNames:
- cpol
- cpol
subresources:
status: {}
validation:
@ -23,14 +23,14 @@ spec:
status: {}
spec:
required:
- rules
- rules
properties:
# default values to be handled by user
# default values to be handled by user
validationFailureAction:
type: string
enum:
- enforce # blocks the resorce api-reques if a rule fails.
- audit # allows resource creation and reports the failed validation rules as violations. Default
enum:
- enforce # blocks the resorce api-reques if a rule fails.
- audit # allows resource creation and reports the failed validation rules as violations. Default
background:
type: boolean
rules:
@ -38,15 +38,15 @@ spec:
items:
type: object
required:
- name
- match
- name
- match
properties:
name:
type: string
match:
type: object
required:
- resources
- resources
properties:
roles:
type: array
@ -61,8 +61,8 @@ spec:
items:
type: object
required:
- kind
- name
- kind
- name
properties:
kind:
type: string
@ -101,8 +101,8 @@ spec:
items:
type: object
required:
- key
- operator
- key
- operator
properties:
key:
type: string
@ -128,8 +128,8 @@ spec:
items:
type: object
required:
- kind
- name
- kind
- name
properties:
kind:
type: string
@ -167,8 +167,8 @@ spec:
items:
type: object
required:
- key
- operator
- key
- operator
properties:
key:
type: string
@ -183,9 +183,9 @@ spec:
items:
type: object
required:
- key # can be of any type
- operator # typed
- value # can be of any type
- key # can be of any type
- operator # typed
- value # can be of any type
mutate:
type: object
properties:
@ -198,17 +198,17 @@ spec:
items:
type: object
required:
- path
- op
- path
- op
properties:
path:
type: string
op:
type: string
enum:
- add
- replace
- remove
- add
- replace
- remove
value: {}
validate:
type: object
@ -231,24 +231,24 @@ spec:
operator:
type: string
enum:
- Equal
- Equals
- NotEqual
- NotEquals
- In
- NotIn
- Equal
- Equals
- NotEqual
- NotEquals
- In
- NotIn
key:
type: string
value:
anyOf:
- type: string
- type: array
items: {}
- type: string
- type: array
items: {}
generate:
type: object
required:
- kind
- name
- kind
- name
properties:
apiVersion:
type: string
@ -260,11 +260,11 @@ spec:
type: string
synchronize:
type: boolean
clone:
clone:
type: object
required:
- namespace
- name
- namespace
- name
properties:
namespace:
type: string
@ -288,7 +288,7 @@ spec:
plural: policies
singular: policy
shortNames:
- pol
- pol
subresources:
status: {}
validation:
@ -297,14 +297,14 @@ spec:
status: {}
spec:
required:
- rules
- rules
properties:
# default values to be handled by user
# default values to be handled by user
validationFailureAction:
type: string
enum:
- enforce # blocks the resorce api-reques if a rule fails.
- audit # allows resource creation and reports the failed validation rules as violations. Default
enum:
- enforce # blocks the resorce api-reques if a rule fails.
- audit # allows resource creation and reports the failed validation rules as violations. Default
background:
type: boolean
rules:
@ -312,15 +312,15 @@ spec:
items:
type: object
required:
- name
- match
- name
- match
properties:
name:
type: string
match:
type: object
required:
- resources
- resources
properties:
roles:
type: array
@ -335,8 +335,8 @@ spec:
items:
type: object
required:
- kind
- name
- kind
- name
properties:
kind:
type: string
@ -367,8 +367,8 @@ spec:
items:
type: object
required:
- key
- operator
- key
- operator
properties:
key:
type: string
@ -394,8 +394,8 @@ spec:
items:
type: object
required:
- kind
- name
- kind
- name
properties:
kind:
type: string
@ -425,8 +425,8 @@ spec:
items:
type: object
required:
- key
- operator
- key
- operator
properties:
key:
type: string
@ -441,9 +441,9 @@ spec:
items:
type: object
required:
- key # can be of any type
- operator # typed
- value # can be of any type
- key # can be of any type
- operator # typed
- value # can be of any type
mutate:
type: object
properties:
@ -456,17 +456,17 @@ spec:
items:
type: object
required:
- path
- op
- path
- op
properties:
path:
type: string
op:
type: string
enum:
- add
- replace
- remove
- add
- replace
- remove
value: {}
validate:
type: object
@ -489,24 +489,24 @@ spec:
operator:
type: string
enum:
- Equal
- Equals
- NotEqual
- NotEquals
- In
- NotIn
- Equal
- Equals
- NotEqual
- NotEquals
- In
- NotIn
key:
type: string
value:
anyOf:
- type: string
- type: array
items: {}
- type: string
- type: array
items: {}
generate:
type: object
required:
- kind
- name
- kind
- name
properties:
apiVersion:
type: string
@ -518,11 +518,11 @@ spec:
type: string
synchronize:
type: boolean
clone:
clone:
type: object
required:
- namespace
- name
- namespace
- name
properties:
namespace:
type: string
@ -546,41 +546,41 @@ spec:
plural: clusterpolicyviolations
singular: clusterpolicyviolation
shortNames:
- cpolv
- cpolv
subresources:
status: {}
additionalPrinterColumns:
- name: Policy
type: string
description: The policy that resulted in the violation
JSONPath: .spec.policy
- name: ResourceKind
type: string
description: The resource kind that cause the violation
JSONPath: .spec.resource.kind
- name: ResourceName
type: string
description: The resource name that caused the violation
JSONPath: .spec.resource.name
- name: Age
type: date
JSONPath: .metadata.creationTimestamp
- name: Policy
type: string
description: The policy that resulted in the violation
JSONPath: .spec.policy
- name: ResourceKind
type: string
description: The resource kind that cause the violation
JSONPath: .spec.resource.kind
- name: ResourceName
type: string
description: The resource name that caused the violation
JSONPath: .spec.resource.name
- name: Age
type: date
JSONPath: .metadata.creationTimestamp
validation:
openAPIV3Schema:
properties:
spec:
required:
- policy
- resource
- rules
- policy
- resource
- rules
properties:
policy:
type: string
resource:
type: object
required:
- kind
- name
- kind
- name
properties:
kind:
type: string
@ -591,9 +591,9 @@ spec:
items:
type: object
required:
- name
- type
- message
- name
- type
- message
properties:
name:
type: string
@ -618,41 +618,41 @@ spec:
plural: policyviolations
singular: policyviolation
shortNames:
- polv
- polv
subresources:
status: {}
additionalPrinterColumns:
- name: Policy
type: string
description: The policy that resulted in the violation
JSONPath: .spec.policy
- name: ResourceKind
type: string
description: The resource kind that cause the violation
JSONPath: .spec.resource.kind
- name: ResourceName
type: string
description: The resource name that caused the violation
JSONPath: .spec.resource.name
- name: Age
type: date
JSONPath: .metadata.creationTimestamp
- name: Policy
type: string
description: The policy that resulted in the violation
JSONPath: .spec.policy
- name: ResourceKind
type: string
description: The resource kind that cause the violation
JSONPath: .spec.resource.kind
- name: ResourceName
type: string
description: The resource name that caused the violation
JSONPath: .spec.resource.name
- name: Age
type: date
JSONPath: .metadata.creationTimestamp
validation:
openAPIV3Schema:
properties:
spec:
required:
- policy
- resource
- rules
- policy
- resource
- rules
properties:
policy:
type: string
resource:
type: object
required:
- kind
- name
- kind
- name
properties:
kind:
type: string
@ -663,9 +663,9 @@ spec:
items:
type: object
required:
- name
- type
- message
- name
- type
- message
properties:
name:
type: string
@ -690,52 +690,52 @@ spec:
plural: generaterequests
singular: generaterequest
shortNames:
- gr
- gr
subresources:
status: {}
additionalPrinterColumns:
- name: Policy
type: string
description: The policy that resulted in the violation
JSONPath: .spec.policy
- name: ResourceKind
type: string
description: The resource kind that cause the violation
JSONPath: .spec.resource.kind
- name: ResourceName
type: string
description: The resource name that caused the violation
JSONPath: .spec.resource.name
- name: ResourceNamespace
type: string
description: The resource namespace that caused the violation
JSONPath: .spec.resource.namespace
- name: status
type : string
description: Current state of generate request
JSONPath: .status.state
- name: Age
type: date
JSONPath: .metadata.creationTimestamp
- name: Policy
type: string
description: The policy that resulted in the violation
JSONPath: .spec.policy
- name: ResourceKind
type: string
description: The resource kind that cause the violation
JSONPath: .spec.resource.kind
- name: ResourceName
type: string
description: The resource name that caused the violation
JSONPath: .spec.resource.name
- name: ResourceNamespace
type: string
description: The resource namespace that caused the violation
JSONPath: .spec.resource.namespace
- name: status
type : string
description: Current state of generate request
JSONPath: .status.state
- name: Age
type: date
JSONPath: .metadata.creationTimestamp
validation:
openAPIV3Schema:
properties:
spec:
required:
- policy
- resource
- policy
- resource
properties:
policy:
type: string
resource:
type: object
required:
- kind
- name
- kind
- name
properties:
kind:
type: string
name:
name:
type: string
namespace:
type: string
type: string

View file

@ -832,8 +832,10 @@ rules:
- rolebindings
- clusterrolebindings
- configmaps
- namespaces
verbs:
- watch
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole

View file

@ -832,8 +832,10 @@ rules:
- rolebindings
- clusterrolebindings
- configmaps
- namespaces
verbs:
- watch
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole

View file

@ -158,8 +158,10 @@ rules:
- rolebindings
- clusterrolebindings
- configmaps
- namespaces
verbs:
- watch
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole

View file

@ -27,6 +27,7 @@ type PolicyResponse struct {
Rules []RuleResponse `json:"rules"`
// ValidationFailureAction: audit(default if not set),enforce
ValidationFailureAction string
}
//ResourceSpec resource action applied on

View file

@ -175,12 +175,14 @@ func (c *Controller) deleteGR(obj interface{}) {
for _, resource := range gr.Status.GeneratedResources {
r, err := c.client.GetResource(resource.APIVersion, resource.Kind, resource.Namespace, resource.Name)
if err != nil {
logger.Error(err, "Generated resource is not deleted", "Resource", r.GetName())
logger.Error(err, "Generated resource is not deleted", "Resource", resource.Name)
return
}
labels := r.GetLabels()
if labels["policy.kyverno.io/synchronize"] == "enable" {
if err := c.client.DeleteResource(r.GetAPIVersion(), r.GetKind(), r.GetNamespace(), r.GetName(), false); err != nil {
logger.Error(err, "Generated resource is not deleted", "Resource", r.GetName())
return
}
}
}

View file

@ -1,8 +1,6 @@
package generate
import (
"time"
"github.com/go-logr/logr"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
@ -20,6 +18,7 @@ import (
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
"time"
)
const (
@ -204,7 +203,8 @@ func (c *Controller) deleteGR(obj interface{}) {
for _, resource := range gr.Status.GeneratedResources {
r, err := c.client.GetResource(resource.APIVersion, resource.Kind, resource.Namespace, resource.Name)
if err != nil {
logger.Error(err, "Generated resource is not deleted", "Resource", r.GetName())
logger.Error(err, "Generated resource is not deleted", "Resource", resource.Name)
continue
}
labels := r.GetLabels()
if labels["policy.kyverno.io/synchronize"] == "enable" {

View file

@ -108,8 +108,8 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
logger.V(4).Info("policy does not apply to resource")
return nil, fmt.Errorf("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
}
for i, r := range engineResponse.PolicyResponse.Rules {
var rules []response.RuleResponse
for _, r := range engineResponse.PolicyResponse.Rules {
if !r.Success {
grList, err := c.kyvernoClient.KyvernoV1().GenerateRequests(config.KubePolicyNamespace).List(metav1.ListOptions{})
if err != nil {
@ -123,14 +123,24 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
}
}
}
if len(engineResponse.PolicyResponse.Rules) > 1 {
engineResponse.PolicyResponse.Rules = append(engineResponse.PolicyResponse.Rules[:i], engineResponse.PolicyResponse.Rules[i+1:]...)
continue
} else if len(engineResponse.PolicyResponse.Rules) == 1 {
engineResponse.PolicyResponse.Rules = []response.RuleResponse{}
} else {
rules = append(rules, r)
}
}
engineResponse.PolicyResponse.Rules = []response.RuleResponse{}
for _, v := range policy.Spec.Rules {
for _, r := range rules {
if policy.Name == engineResponse.PolicyResponse.Policy && r.Name == v.Name {
if len(v.MatchResources.ResourceDescription.Kinds) > 0 && (len(v.MatchResources.ResourceDescription.Annotations) == 0 || len(v.MatchResources.ResourceDescription.Selector.MatchLabels) == 0) {
continue
} else {
engineResponse.PolicyResponse.Rules = append(engineResponse.PolicyResponse.Rules, r)
}
}
}
}
// Apply the generate rule on resource
return c.applyGeneratePolicy(logger, policyContext, gr)
}
@ -160,7 +170,23 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
continue
}
startTime := time.Now()
genResource, err := applyRule(log, c.client, rule, resource, ctx, policy.Name, gr)
processExisting := false
for _, v := range policy.Spec.Rules {
if policy.Name == gr.Spec.Policy {
if len(v.MatchResources.ResourceDescription.Kinds) > 0 && (len(v.MatchResources.ResourceDescription.Annotations) == 0 || len(v.MatchResources.ResourceDescription.Selector.MatchLabels) == 0) {
processExisting = func() bool {
rcreationTime := resource.GetCreationTimestamp()
pcreationTime := policy.GetCreationTimestamp()
return rcreationTime.Before(&pcreationTime)
}()
}
}
}
genResource, err := applyRule(log, c.client, rule, resource, ctx, policy.Name, gr, processExisting)
if err != nil {
return nil, err
}
@ -217,7 +243,7 @@ func updateGenerateExecutionTime(newTime time.Duration, oldAverageTimeString str
return time.Duration(newAverageTimeInNanoSeconds) * time.Nanosecond
}
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy string, gr kyverno.GenerateRequest) (kyverno.ResourceSpec, error) {
func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy string, gr kyverno.GenerateRequest, processExisting bool) (kyverno.ResourceSpec, error) {
var rdata map[string]interface{}
var err error
var mode ResourceMode
@ -227,7 +253,6 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
if err != nil {
return noGenResource, err
}
// Variable substitutions
// format : {{<variable_name}}
// - if there is variables that are not defined the context -> results in error and rule is not applied
@ -255,7 +280,6 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
if err != nil {
return noGenResource, err
}
// Resource to be generated
newGenResource := kyverno.ResourceSpec{
APIVersion: genAPIVersion,
@ -271,7 +295,6 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
if err != nil {
return noGenResource, err
}
if genData != nil {
rdata, mode, err = manageData(log, genAPIVersion, genKind, genNamespace, genName, genData, client, resource)
} else {
@ -286,7 +309,9 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
// existing resource contains the configuration
return newGenResource, nil
}
if processExisting {
return noGenResource, nil
}
logger := log.WithValues("genKind", genKind, "genAPIVersion", genAPIVersion, "genNamespace", genNamespace, "genName", genName)
// build the resource template
@ -297,24 +322,23 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
if newResource.GetKind() == "" {
newResource.SetKind(genKind)
}
newResource.SetAPIVersion(genAPIVersion)
// manage labels
// - app.kubernetes.io/managed-by: kyverno
// - kyverno.io/generated-by: kind/namespace/name (trigger resource)
manageLabels(newResource, resource)
// Add Synchronize label
label := newResource.GetLabels()
if rule.Generation.Synchronize {
label["policy.kyverno.io/synchronize"] = "enable"
} else {
label["policy.kyverno.io/synchronize"] = "disable"
}
label["policy.kyverno.io/policy-name"] = policy
label["policy.kyverno.io/gr-name"] = gr.Name
newResource.SetLabels(label)
if mode == Create {
if rule.Generation.Synchronize {
label["policy.kyverno.io/synchronize"] = "enable"
} else {
label["policy.kyverno.io/synchronize"] = "disable"
}
// Reset resource version
newResource.SetResourceVersion("")
// Create the resource
@ -327,25 +351,48 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
logger.V(4).Info("created new resource")
} else if mode == Update {
var isUpdate bool
label := newResource.GetLabels()
if label != nil {
if rule.Generation.Synchronize {
logger.V(4).Info("updating existing resource")
// Update the resource
_, err := client.UpdateResource(genAPIVersion, genKind, genNamespace, newResource, false)
if err != nil {
logger.Error(err, "updating existing resource")
// Failed to update resource
return noGenResource, err
}
logger.V(4).Info("updated new resource")
} else {
logger.V(4).Info("Synchronize resource is disabled")
isUpdate = false
if rule.Generation.Synchronize {
if label["policy.kyverno.io/synchronize"] == "enable" {
isUpdate = true
}
} else {
logger.V(4).Info("Synchronize resource is disabled")
if label["policy.kyverno.io/synchronize"] == "enable" {
isUpdate = true
}
}
if rule.Generation.Synchronize {
label["policy.kyverno.io/synchronize"] = "enable"
} else {
label["policy.kyverno.io/synchronize"] = "disable"
}
if isUpdate {
logger.V(4).Info("updating existing resource")
// Update the resource
newResource.SetLabels(label)
_, err := client.UpdateResource(genAPIVersion, genKind, genNamespace, newResource, false)
if err != nil {
logger.Error(err, "updating existing resource")
// Failed to update resource
return noGenResource, err
}
logger.V(4).Info("updated new resource")
}else{
resource := &unstructured.Unstructured{}
resource.SetUnstructuredContent(rdata)
resource.SetLabels(label)
_, err := client.UpdateResource(genAPIVersion, genKind, genNamespace, resource, false)
if err != nil {
logger.Error(err, "updating existing resource")
// Failed to update resource
return noGenResource, err
}
logger.V(4).Info("updated new resource")
}
logger.V(4).Info("Synchronize resource is disabled")
}
return newGenResource, nil
}
@ -353,24 +400,19 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
func manageData(log logr.Logger, apiVersion, kind, namespace, name string, data map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
// check if resource to be generated exists
obj, err := client.GetResource(apiVersion, kind, namespace, name)
if apierrors.IsNotFound(err) {
log.Error(err, "resource does not exist, will try to create", "genKind", kind, "genAPIVersion", apiVersion, "genNamespace", namespace, "genName", name)
return data, Create, nil
}
if err != nil {
if apierrors.IsNotFound(err) {
log.Error(err, "resource does not exist, will try to create", "genKind", kind, "genAPIVersion", apiVersion, "genNamespace", namespace, "genName", name)
return data, Create, nil
}
//something wrong while fetching resource
// client-errors
return nil, Skip, err
}
// Resource exists; verfiy the content of the resource
err = checkResource(log, data, obj)
if err == nil {
// Existing resource does contain the mentioned configuration in spec, skip processing the resource as it is already in expected state
return nil, Skip, nil
}
log.Info("to be generated resoruce already exists, but is missing the specifeid configurations, will try to update", "genKind", kind, "genAPIVersion", apiVersion, "genNamespace", namespace, "genName", name)
return data, Update, nil
updateObj := &unstructured.Unstructured{}
updateObj.SetUnstructuredContent(data)
updateObj.SetResourceVersion(obj.GetResourceVersion())
return updateObj.UnstructuredContent(), Update, nil
}
func manageClone(log logr.Logger, apiVersion, kind, namespace, name string, clone map[string]interface{}, client *dclient.Client, resource unstructured.Unstructured) (map[string]interface{}, ResourceMode, error) {
@ -409,13 +451,6 @@ func manageClone(log logr.Logger, apiVersion, kind, namespace, name string, clon
return obj.UnstructuredContent(), Update, nil
}
//TODO: check this
if !apierrors.IsNotFound(err) {
log.Error(err, "reference/clone resource is not found", "genKind", kind, "genAPIVersion", apiVersion, "genNamespace", namespace, "genName", name)
//something wrong while fetching resource
return nil, Skip, err
}
// create the resource based on the reference clone
return obj.UnstructuredContent(), Create, nil

View file

@ -1,6 +1,9 @@
package policy
import (
"fmt"
"k8s.io/apimachinery/pkg/labels"
"math/rand"
"time"
informers "k8s.io/client-go/informers/core/v1"
@ -58,6 +61,9 @@ type PolicyController struct {
// npLister can list/get namespace policy from the shared informer's store
npLister kyvernolister.PolicyLister
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestLister
// pvLister can list/get policy violation from the shared informer's store
cpvLister kyvernolister.ClusterPolicyViolationLister
@ -82,6 +88,8 @@ type PolicyController struct {
// nsListerSynced returns true if the namespace store has been synced at least once
nsListerSynced cache.InformerSynced
// grListerSynced returns true if the generate request store has been synced at least once
grListerSynced cache.InformerSynced
// Resource manager, manages the mapping for already processed resource
rm resourceManager
@ -91,6 +99,7 @@ type PolicyController struct {
// policy violation generator
pvGenerator policyviolation.GeneratorInterface
// resourceWebhookWatcher queues the webhook creation request, creates the webhook
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister
@ -104,6 +113,7 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
npInformer kyvernoinformer.PolicyInformer,
cpvInformer kyvernoinformer.ClusterPolicyViolationInformer,
nspvInformer kyvernoinformer.PolicyViolationInformer,
grInformer kyvernoinformer.GenerateRequestInformer,
configHandler config.Interface, eventGen event.Interface,
pvGenerator policyviolation.GeneratorInterface,
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister,
@ -162,12 +172,13 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
pc.cpvLister = cpvInformer.Lister()
pc.nspvLister = nspvInformer.Lister()
pc.nsLister = namespaces.Lister()
pc.grLister = grInformer.Lister()
pc.pListerSynced = pInformer.Informer().HasSynced
pc.npListerSynced = npInformer.Informer().HasSynced
pc.cpvListerSynced = cpvInformer.Informer().HasSynced
pc.nspvListerSynced = nspvInformer.Informer().HasSynced
pc.nsListerSynced = namespaces.Informer().HasSynced
pc.grListerSynced = grInformer.Informer().HasSynced
// resource manager
// rebuild after 300 seconds/ 5 mins
@ -308,7 +319,7 @@ func (pc *PolicyController) Run(workers int, stopCh <-chan struct{}) {
logger.Info("starting")
defer logger.Info("shutting down")
if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.cpvListerSynced, pc.nspvListerSynced, pc.nsListerSynced) {
if !cache.WaitForCacheSync(stopCh, pc.pListerSynced, pc.cpvListerSynced, pc.nspvListerSynced, pc.nsListerSynced,pc.grListerSynced) {
logger.Info("failed to sync informer cache")
return
}
@ -373,6 +384,11 @@ func (pc *PolicyController) syncPolicy(key string) error {
namespace, key, isNamespacedPolicy := getIsNamespacedPolicy(key)
var policy *kyverno.ClusterPolicy
var err error
grList, err := pc.grLister.List(labels.Everything())
if err != nil {
logger.Error(err, "failed to list generate request")
}
if !isNamespacedPolicy {
policy, err = pc.pLister.Get(key)
} else {
@ -380,9 +396,17 @@ func (pc *PolicyController) syncPolicy(key string) error {
nspolicy, err = pc.npLister.Policies(namespace).Get(key)
policy = convertPolicyToClusterPolicy(nspolicy)
}
if errors.IsNotFound(err) {
go pc.deletePolicyViolations(key)
if errors.IsNotFound(err) {
for _, v := range grList {
if key == v.Spec.Policy {
err := pc.kyvernoClient.KyvernoV1().GenerateRequests(config.KubePolicyNamespace).Delete(v.GetName(),&metav1.DeleteOptions{})
if err != nil {
logger.Error(err, "failed to delete gr")
}
}
}
go pc.deletePolicyViolations(key)
// remove webhook configurations if there are no policies
if err := pc.removeResourceWebhookConfiguration(); err != nil {
logger.Error(err, "failed to remove resource webhook configurations")
@ -390,11 +414,20 @@ func (pc *PolicyController) syncPolicy(key string) error {
return nil
}
if err != nil {
return err
for _, v := range grList {
if policy.Name == v.Spec.Policy {
v.SetLabels(map[string]string{
"policy-update" :fmt.Sprintf("revision-count-%d",rand.Intn(100000)),
})
_,err := pc.kyvernoClient.KyvernoV1().GenerateRequests(config.KubePolicyNamespace).Update(v)
if err != nil {
logger.Error(err, "failed to update gr")
return err
}
}
}
pc.resourceWebhookWatcher.RegisterResourceWebhook()
engineResponses := pc.processExistingResources(policy)

View file

@ -90,6 +90,7 @@ func (g *Generator) processApply() {
func (g *Generator) generate(grSpec kyverno.GenerateRequestSpec, action v1beta1.Operation) error {
// create/update a generate request
if err := retryApplyResource(g.client, grSpec, g.log, action); err != nil {
return err
}
@ -125,10 +126,10 @@ func retryApplyResource(client *kyvernoclient.Clientset,
}
for i, v := range grList.Items {
if grSpec.Policy == v.Spec.Policy && grSpec.Resource.Name == v.Spec.Resource.Name && grSpec.Resource.Kind == v.Spec.Resource.Kind && grSpec.Resource.Namespace == v.Spec.Resource.Namespace {
gr.SetLabels(map[string]string{
"resources-update": "true",
})
v.Spec.Context = gr.Spec.Context
v.Spec.Policy = gr.Spec.Policy
v.Spec.Resource = gr.Spec.Resource

View file

@ -47,10 +47,11 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
}
// engine.Generate returns a list of rules that are applicable on this resource
var rules []response.RuleResponse
for _, policy := range policies {
policyContext.Policy = *policy
engineResponse := engine.Generate(policyContext)
for i, rule := range engineResponse.PolicyResponse.Rules {
for _, rule := range engineResponse.PolicyResponse.Rules {
if !rule.Success {
grList, err := ws.kyvernoClient.KyvernoV1().GenerateRequests(config.KubePolicyNamespace).List(metav1.ListOptions{})
if err != nil {
@ -64,15 +65,14 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
}
}
}
if len(engineResponse.PolicyResponse.Rules) > 1 {
engineResponse.PolicyResponse.Rules = append(engineResponse.PolicyResponse.Rules[:i], engineResponse.PolicyResponse.Rules[i+1:]...)
continue
} else if len(engineResponse.PolicyResponse.Rules) == 1 {
engineResponse.PolicyResponse.Rules = []response.RuleResponse{}
}
}else{
rules = append(rules,rule)
}
}
if len(engineResponse.PolicyResponse.Rules) > 0 {
if len(rules) > 0 {
engineResponse.PolicyResponse.Rules = rules
// some generate rules do apply to the resource
engineResponses = append(engineResponses, engineResponse)
ws.statusListener.Send(generateStats{
@ -81,6 +81,7 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
}
}
// Adds Generate Request to a channel(queue size 1000) to generators
if failedResponse := applyGenerateRequest(ws.grGenerator, userRequestInfo, request.Operation, engineResponses...); err != nil {
// report failure event