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:
parent
154b1c1eb9
commit
b7524467a3
13 changed files with 313 additions and 231 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -832,8 +832,10 @@ rules:
|
|||
- rolebindings
|
||||
- clusterrolebindings
|
||||
- configmaps
|
||||
- namespaces
|
||||
verbs:
|
||||
- watch
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
|
|
|
@ -832,8 +832,10 @@ rules:
|
|||
- rolebindings
|
||||
- clusterrolebindings
|
||||
- configmaps
|
||||
- namespaces
|
||||
verbs:
|
||||
- watch
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
|
|
|
@ -158,8 +158,10 @@ rules:
|
|||
- rolebindings
|
||||
- clusterrolebindings
|
||||
- configmaps
|
||||
- namespaces
|
||||
verbs:
|
||||
- watch
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue