mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
refactor: update updaterequest to be created for each policy (#10793)
* chore: remove v1beta1 updaterequest definitions Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: update UR to map a policy instead a rule; adapt UR mapping changes for admission review Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: update code-gen Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: linter Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: remove unused function Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: add missing files Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: add missing files Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: update ur in policy controller Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: update crds Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: adapt ur changes in the background controller Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: linter Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: more linter Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: modify mapping relationship for deletion events Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: remedy missing target for policy application Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: fetching logic for triggers Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: clean up targets upon policy deletion Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: update crds Signed-off-by: ShutingZhao <shuting@nirmata.com> * merge main Signed-off-by: ShutingZhao <shuting@nirmata.com> * merge main Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: adds delay before assertion Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: update docs Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: wrong yaml format Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: update error handling logic Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix(attempt): enable more debug info Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix(attempt): enable debug log Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix(attempt): enable debug log Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix(attempt): enable debug log Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: makefile to update ur crds Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: generate existing Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: skip empty ur generation Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: update install.yaml Signed-off-by: ShutingZhao <shuting@nirmata.com> --------- Signed-off-by: ShutingZhao <shuting@nirmata.com>
This commit is contained in:
parent
de37a045be
commit
481798c836
43 changed files with 1002 additions and 1577 deletions
8
.github/actions/kyverno-logs/action.yaml
vendored
8
.github/actions/kyverno-logs/action.yaml
vendored
|
@ -14,15 +14,9 @@ runs:
|
|||
run: |
|
||||
kubectl -n kyverno get pod
|
||||
kubectl -n kyverno describe pod | grep -i events -A10
|
||||
- shell: bash
|
||||
run: |
|
||||
kubectl -n kyverno logs deploy/kyverno-admission-controller --all-containers -p || true
|
||||
kubectl -n kyverno logs deploy/kyverno-reports-controller --all-containers -p || true
|
||||
kubectl -n kyverno logs deploy/kyverno-cleanup-controller --all-containers -p || true
|
||||
kubectl -n kyverno logs deploy/kyverno-background-controller --all-containers -p || true
|
||||
- shell: bash
|
||||
run: |
|
||||
kubectl -n kyverno logs deploy/kyverno-admission-controller --all-containers
|
||||
kubectl -n kyverno logs deploy/kyverno-background-controller --all-containers
|
||||
kubectl -n kyverno logs deploy/kyverno-reports-controller --all-containers
|
||||
kubectl -n kyverno logs deploy/kyverno-cleanup-controller --all-containers
|
||||
kubectl -n kyverno logs deploy/kyverno-background-controller --all-containers
|
||||
|
|
2
Makefile
2
Makefile
|
@ -501,7 +501,7 @@ codegen-client-all: codegen-client-wrappers
|
|||
codegen-crds-kyverno: ## Generate kyverno CRDs
|
||||
@echo Generate kyverno crds... >&2
|
||||
@rm -rf $(CRDS_PATH)/kyverno && mkdir -p $(CRDS_PATH)/kyverno
|
||||
@go run ./hack/controller-gen -- paths=./api/kyverno/... crd:crdVersions=v1,ignoreUnexportedFields=true,generateEmbeddedObjectMeta=false output:dir=$(CRDS_PATH)/kyverno
|
||||
@go run ./hack/controller-gen -- paths=./api/kyverno/v1/... paths=./api/kyverno/v2/... paths=./api/kyverno/v2alpha1/... paths=./api/kyverno/v2beta1/... crd:crdVersions=v1,ignoreUnexportedFields=true,generateEmbeddedObjectMeta=false output:dir=$(CRDS_PATH)/kyverno
|
||||
|
||||
.PHONY: codegen-crds-policyreport
|
||||
codegen-crds-policyreport: ## Generate policy reports CRDs
|
||||
|
|
|
@ -10,9 +10,5 @@ const (
|
|||
|
||||
// URGeneratePolicyLabel adds the policy name to URs for generate policies
|
||||
URGeneratePolicyLabel = "generate.kyverno.io/policy-name"
|
||||
URGenerateResourceNameLabel = "generate.kyverno.io/resource-name"
|
||||
URGenerateResourceUIDLabel = "generate.kyverno.io/resource-uid"
|
||||
URGenerateResourceNSLabel = "generate.kyverno.io/resource-namespace"
|
||||
URGenerateResourceKindLabel = "generate.kyverno.io/resource-kind"
|
||||
URGenerateRetryCountAnnotation = "generate.kyverno.io/retry-count"
|
||||
)
|
||||
|
|
|
@ -82,6 +82,31 @@ type UpdateRequestSpec struct {
|
|||
// Specifies the name of the policy.
|
||||
Policy string `json:"policy" yaml:"policy"`
|
||||
|
||||
// RuleContext is the associate context to apply rules.
|
||||
// optional
|
||||
RuleContext []RuleContext `json:"ruleContext,omitempty" yaml:"ruleContext,omitempty"`
|
||||
|
||||
// Rule is the associate rule name of the current UR.
|
||||
Rule string `json:"rule" yaml:"rule"`
|
||||
|
||||
// DeleteDownstream represents whether the downstream needs to be deleted.
|
||||
// Deprecated
|
||||
DeleteDownstream bool `json:"deleteDownstream" yaml:"deleteDownstream"`
|
||||
|
||||
// Synchronize represents the sync behavior of the corresponding rule
|
||||
// Optional. Defaults to "false" if not specified.
|
||||
// Deprecated, will be removed in 1.14.
|
||||
Synchronize bool `json:"synchronize,omitempty" yaml:"synchronize,omitempty"`
|
||||
|
||||
// ResourceSpec is the information to identify the trigger resource.
|
||||
Resource kyvernov1.ResourceSpec `json:"resource" yaml:"resource"`
|
||||
|
||||
// Context represents admission request context.
|
||||
// It is used upon admission review only and is shared across rules within the same UR.
|
||||
Context UpdateRequestSpecContext `json:"context" yaml:"context"`
|
||||
}
|
||||
|
||||
type RuleContext struct {
|
||||
// Rule is the associate rule name of the current UR.
|
||||
Rule string `json:"rule" yaml:"rule"`
|
||||
|
||||
|
@ -93,10 +118,7 @@ type UpdateRequestSpec struct {
|
|||
Synchronize bool `json:"synchronize,omitempty" yaml:"synchronize,omitempty"`
|
||||
|
||||
// ResourceSpec is the information to identify the trigger resource.
|
||||
Resource kyvernov1.ResourceSpec `json:"resource" yaml:"resource"`
|
||||
|
||||
// Context ...
|
||||
Context UpdateRequestSpecContext `json:"context" yaml:"context"`
|
||||
Trigger kyvernov1.ResourceSpec `json:"trigger" yaml:"resource"`
|
||||
}
|
||||
|
||||
// UpdateRequestSpecContext stores the context to be shared.
|
||||
|
|
|
@ -433,6 +433,23 @@ func (in *RequestInfo) DeepCopy() *RequestInfo {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RuleContext) DeepCopyInto(out *RuleContext) {
|
||||
*out = *in
|
||||
out.Trigger = in.Trigger
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuleContext.
|
||||
func (in *RuleContext) DeepCopy() *RuleContext {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RuleContext)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UpdateRequest) DeepCopyInto(out *UpdateRequest) {
|
||||
*out = *in
|
||||
|
@ -497,6 +514,11 @@ func (in *UpdateRequestList) DeepCopyObject() runtime.Object {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UpdateRequestSpec) DeepCopyInto(out *UpdateRequestSpec) {
|
||||
*out = *in
|
||||
if in.RuleContext != nil {
|
||||
in, out := &in.RuleContext, &out.RuleContext
|
||||
*out = make([]RuleContext, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.Resource = in.Resource
|
||||
in.Context.DeepCopyInto(&out.Context)
|
||||
return
|
||||
|
|
|
@ -24,392 +24,6 @@ spec:
|
|||
singular: updaterequest
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.policy
|
||||
name: Policy
|
||||
type: string
|
||||
- jsonPath: .spec.rule
|
||||
name: Rule
|
||||
type: string
|
||||
- jsonPath: .spec.requestType
|
||||
name: RuleType
|
||||
type: string
|
||||
- jsonPath: .spec.resource.kind
|
||||
name: ResourceKind
|
||||
type: string
|
||||
- jsonPath: .spec.resource.name
|
||||
name: ResourceName
|
||||
type: string
|
||||
- jsonPath: .spec.resource.namespace
|
||||
name: ResourceNamespace
|
||||
type: string
|
||||
- jsonPath: .status.state
|
||||
name: status
|
||||
type: string
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
deprecated: true
|
||||
name: v1beta1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: UpdateRequest is a request to process mutate and generate rules
|
||||
in background.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ResourceSpec is the information to identify the trigger resource.
|
||||
properties:
|
||||
context:
|
||||
description: Context ...
|
||||
properties:
|
||||
admissionRequestInfo:
|
||||
description: AdmissionRequestInfoObject stores the admission request
|
||||
and operation details
|
||||
properties:
|
||||
admissionRequest:
|
||||
description: AdmissionRequest describes the admission.Attributes
|
||||
for the admission request.
|
||||
properties:
|
||||
dryRun:
|
||||
description: |-
|
||||
DryRun indicates that modifications will definitely not be persisted for this request.
|
||||
Defaults to false.
|
||||
type: boolean
|
||||
kind:
|
||||
description: Kind is the fully-qualified type of object
|
||||
being submitted (for example, v1.Pod or autoscaling.v1.Scale)
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- kind
|
||||
- version
|
||||
type: object
|
||||
name:
|
||||
description: |-
|
||||
Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and
|
||||
rely on the server to generate the name. If that is the case, this field will contain an empty string.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the namespace associated with
|
||||
the request (if any).
|
||||
type: string
|
||||
object:
|
||||
description: Object is the object from the incoming request.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
oldObject:
|
||||
description: OldObject is the existing object. Only populated
|
||||
for DELETE and UPDATE requests.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
operation:
|
||||
description: |-
|
||||
Operation is the operation being performed. This may be different than the operation
|
||||
requested. e.g. a patch can result in either a CREATE or UPDATE Operation.
|
||||
type: string
|
||||
options:
|
||||
description: |-
|
||||
Options is the operation option structure of the operation being performed.
|
||||
e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be
|
||||
different than the options the caller provided. e.g. for a patch request the performed
|
||||
Operation might be a CREATE, in which case the Options will a
|
||||
`meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
requestKind:
|
||||
description: |-
|
||||
RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale).
|
||||
If this is specified and differs from the value in "kind", an equivalent match and conversion was performed.
|
||||
|
||||
|
||||
For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of
|
||||
`apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`,
|
||||
an API request to apps/v1beta1 deployments would be converted and sent to the webhook
|
||||
with `kind: {group:"apps", version:"v1", kind:"Deployment"}` (matching the rule the webhook registered for),
|
||||
and `requestKind: {group:"apps", version:"v1beta1", kind:"Deployment"}` (indicating the kind of the original API request).
|
||||
|
||||
|
||||
See documentation for the "matchPolicy" field in the webhook configuration type for more details.
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- kind
|
||||
- version
|
||||
type: object
|
||||
requestResource:
|
||||
description: |-
|
||||
RequestResource is the fully-qualified resource of the original API request (for example, v1.pods).
|
||||
If this is specified and differs from the value in "resource", an equivalent match and conversion was performed.
|
||||
|
||||
|
||||
For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of
|
||||
`apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`,
|
||||
an API request to apps/v1beta1 deployments would be converted and sent to the webhook
|
||||
with `resource: {group:"apps", version:"v1", resource:"deployments"}` (matching the resource the webhook registered for),
|
||||
and `requestResource: {group:"apps", version:"v1beta1", resource:"deployments"}` (indicating the resource of the original API request).
|
||||
|
||||
|
||||
See documentation for the "matchPolicy" field in the webhook configuration type.
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
resource:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- resource
|
||||
- version
|
||||
type: object
|
||||
requestSubResource:
|
||||
description: |-
|
||||
RequestSubResource is the name of the subresource of the original API request, if any (for example, "status" or "scale")
|
||||
If this is specified and differs from the value in "subResource", an equivalent match and conversion was performed.
|
||||
See documentation for the "matchPolicy" field in the webhook configuration type.
|
||||
type: string
|
||||
resource:
|
||||
description: Resource is the fully-qualified resource
|
||||
being requested (for example, v1.pods)
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
resource:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- resource
|
||||
- version
|
||||
type: object
|
||||
subResource:
|
||||
description: SubResource is the subresource being requested,
|
||||
if any (for example, "status" or "scale")
|
||||
type: string
|
||||
uid:
|
||||
description: |-
|
||||
UID is an identifier for the individual request/response. It allows us to distinguish instances of requests which are
|
||||
otherwise identical (parallel requests, requests when earlier requests did not modify etc)
|
||||
The UID is meant to track the round trip (request/response) between the KAS and the WebHook, not the user request.
|
||||
It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging.
|
||||
type: string
|
||||
userInfo:
|
||||
description: UserInfo is information about the requesting
|
||||
user
|
||||
properties:
|
||||
extra:
|
||||
additionalProperties:
|
||||
description: ExtraValue masks the value so protobuf
|
||||
can generate
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
description: Any additional information provided by
|
||||
the authenticator.
|
||||
type: object
|
||||
groups:
|
||||
description: The names of groups this user is a part
|
||||
of.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
uid:
|
||||
description: |-
|
||||
A unique value that identifies this user across time. If this user is
|
||||
deleted and another user by the same name is added, they will have
|
||||
different UIDs.
|
||||
type: string
|
||||
username:
|
||||
description: The name that uniquely identifies this
|
||||
user among all active users.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- kind
|
||||
- operation
|
||||
- resource
|
||||
- uid
|
||||
- userInfo
|
||||
type: object
|
||||
operation:
|
||||
description: Operation is the type of resource operation being
|
||||
checked for admission control
|
||||
type: string
|
||||
type: object
|
||||
userInfo:
|
||||
description: RequestInfo contains permission info carried in an
|
||||
admission request.
|
||||
properties:
|
||||
clusterRoles:
|
||||
description: ClusterRoles is a list of possible clusterRoles
|
||||
send the request.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
roles:
|
||||
description: Roles is a list of possible role send the request.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
userInfo:
|
||||
description: UserInfo is the userInfo carried in the admission
|
||||
request.
|
||||
properties:
|
||||
extra:
|
||||
additionalProperties:
|
||||
description: ExtraValue masks the value so protobuf
|
||||
can generate
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
description: Any additional information provided by the
|
||||
authenticator.
|
||||
type: object
|
||||
groups:
|
||||
description: The names of groups this user is a part of.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
uid:
|
||||
description: |-
|
||||
A unique value that identifies this user across time. If this user is
|
||||
deleted and another user by the same name is added, they will have
|
||||
different UIDs.
|
||||
type: string
|
||||
username:
|
||||
description: The name that uniquely identifies this user
|
||||
among all active users.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream needs
|
||||
to be deleted.
|
||||
type: boolean
|
||||
policy:
|
||||
description: Specifies the name of the policy.
|
||||
type: string
|
||||
requestType:
|
||||
description: Type represents request type for background processing
|
||||
enum:
|
||||
- mutate
|
||||
- generate
|
||||
type: string
|
||||
resource:
|
||||
description: ResourceSpec is the information to identify the trigger
|
||||
resource.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
name:
|
||||
description: Name specifies the resource name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
uid:
|
||||
description: UID specifies the resource uid.
|
||||
type: string
|
||||
type: object
|
||||
rule:
|
||||
description: Rule is the associate rule name of the current UR.
|
||||
type: string
|
||||
synchronize:
|
||||
description: |-
|
||||
Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to "false" if not specified.
|
||||
type: boolean
|
||||
required:
|
||||
- context
|
||||
- deleteDownstream
|
||||
- policy
|
||||
- resource
|
||||
- rule
|
||||
type: object
|
||||
status:
|
||||
description: Status contains statistics related to update request.
|
||||
properties:
|
||||
generatedResources:
|
||||
description: |-
|
||||
This will track the resources that are updated by the generate Policy.
|
||||
Will be used during clean up resources.
|
||||
items:
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
name:
|
||||
description: Name specifies the resource name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
uid:
|
||||
description: UID specifies the resource uid.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
handler:
|
||||
description: Deprecated
|
||||
type: string
|
||||
message:
|
||||
description: Specifies request status message.
|
||||
type: string
|
||||
retryCount:
|
||||
type: integer
|
||||
state:
|
||||
description: State represents state of the update request.
|
||||
type: string
|
||||
required:
|
||||
- state
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: false
|
||||
subresources:
|
||||
status: {}
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.policy
|
||||
name: Policy
|
||||
|
@ -459,7 +73,9 @@ spec:
|
|||
description: ResourceSpec is the information to identify the trigger resource.
|
||||
properties:
|
||||
context:
|
||||
description: Context ...
|
||||
description: |-
|
||||
Context represents admission request context.
|
||||
It is used upon admission review only and is shared across rules within the same UR.
|
||||
properties:
|
||||
admissionRequestInfo:
|
||||
description: AdmissionRequestInfoObject stores the admission request
|
||||
|
@ -700,8 +316,9 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream needs
|
||||
to be deleted.
|
||||
description: |-
|
||||
DeleteDownstream represents whether the downstream needs to be deleted.
|
||||
Deprecated
|
||||
type: boolean
|
||||
policy:
|
||||
description: Specifies the name of the policy.
|
||||
|
@ -735,10 +352,56 @@ spec:
|
|||
rule:
|
||||
description: Rule is the associate rule name of the current UR.
|
||||
type: string
|
||||
ruleContext:
|
||||
description: |-
|
||||
RuleContext is the associate context to apply rules.
|
||||
optional
|
||||
items:
|
||||
properties:
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream
|
||||
needs to be deleted.
|
||||
type: boolean
|
||||
rule:
|
||||
description: Rule is the associate rule name of the current
|
||||
UR.
|
||||
type: string
|
||||
synchronize:
|
||||
description: |-
|
||||
Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to "false" if not specified.
|
||||
type: boolean
|
||||
trigger:
|
||||
description: ResourceSpec is the information to identify the
|
||||
trigger resource.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
name:
|
||||
description: Name specifies the resource name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
uid:
|
||||
description: UID specifies the resource uid.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- deleteDownstream
|
||||
- rule
|
||||
- trigger
|
||||
type: object
|
||||
type: array
|
||||
synchronize:
|
||||
description: |-
|
||||
Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to "false" if not specified.
|
||||
Deprecated, will be removed in 1.14.
|
||||
type: boolean
|
||||
required:
|
||||
- context
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"io"
|
||||
"strings"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/log"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/store"
|
||||
|
@ -80,23 +78,10 @@ func handleGeneratePolicy(out io.Writer, store *store.Store, generateResponse *e
|
|||
return nil, err
|
||||
}
|
||||
|
||||
gr := kyvernov2.UpdateRequest{
|
||||
Spec: kyvernov2.UpdateRequestSpec{
|
||||
Type: kyvernov2.Generate,
|
||||
Policy: generateResponse.Policy().GetName(),
|
||||
Resource: kyvernov1.ResourceSpec{
|
||||
Kind: generateResponse.Resource.GetKind(),
|
||||
Namespace: generateResponse.Resource.GetNamespace(),
|
||||
Name: generateResponse.Resource.GetName(),
|
||||
APIVersion: generateResponse.Resource.GetAPIVersion(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var newRuleResponse []engineapi.RuleResponse
|
||||
|
||||
for _, rule := range generateResponse.PolicyResponse.Rules {
|
||||
genResource, err := c.ApplyGeneratePolicy(log.Log.V(2), &policyContext, gr, []string{rule.Name()})
|
||||
genResource, err := c.ApplyGeneratePolicy(log.Log.V(2), &policyContext, []string{rule.Name()})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -18,392 +18,6 @@ spec:
|
|||
singular: updaterequest
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.policy
|
||||
name: Policy
|
||||
type: string
|
||||
- jsonPath: .spec.rule
|
||||
name: Rule
|
||||
type: string
|
||||
- jsonPath: .spec.requestType
|
||||
name: RuleType
|
||||
type: string
|
||||
- jsonPath: .spec.resource.kind
|
||||
name: ResourceKind
|
||||
type: string
|
||||
- jsonPath: .spec.resource.name
|
||||
name: ResourceName
|
||||
type: string
|
||||
- jsonPath: .spec.resource.namespace
|
||||
name: ResourceNamespace
|
||||
type: string
|
||||
- jsonPath: .status.state
|
||||
name: status
|
||||
type: string
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
deprecated: true
|
||||
name: v1beta1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: UpdateRequest is a request to process mutate and generate rules
|
||||
in background.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ResourceSpec is the information to identify the trigger resource.
|
||||
properties:
|
||||
context:
|
||||
description: Context ...
|
||||
properties:
|
||||
admissionRequestInfo:
|
||||
description: AdmissionRequestInfoObject stores the admission request
|
||||
and operation details
|
||||
properties:
|
||||
admissionRequest:
|
||||
description: AdmissionRequest describes the admission.Attributes
|
||||
for the admission request.
|
||||
properties:
|
||||
dryRun:
|
||||
description: |-
|
||||
DryRun indicates that modifications will definitely not be persisted for this request.
|
||||
Defaults to false.
|
||||
type: boolean
|
||||
kind:
|
||||
description: Kind is the fully-qualified type of object
|
||||
being submitted (for example, v1.Pod or autoscaling.v1.Scale)
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- kind
|
||||
- version
|
||||
type: object
|
||||
name:
|
||||
description: |-
|
||||
Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and
|
||||
rely on the server to generate the name. If that is the case, this field will contain an empty string.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the namespace associated with
|
||||
the request (if any).
|
||||
type: string
|
||||
object:
|
||||
description: Object is the object from the incoming request.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
oldObject:
|
||||
description: OldObject is the existing object. Only populated
|
||||
for DELETE and UPDATE requests.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
operation:
|
||||
description: |-
|
||||
Operation is the operation being performed. This may be different than the operation
|
||||
requested. e.g. a patch can result in either a CREATE or UPDATE Operation.
|
||||
type: string
|
||||
options:
|
||||
description: |-
|
||||
Options is the operation option structure of the operation being performed.
|
||||
e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be
|
||||
different than the options the caller provided. e.g. for a patch request the performed
|
||||
Operation might be a CREATE, in which case the Options will a
|
||||
`meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
requestKind:
|
||||
description: |-
|
||||
RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale).
|
||||
If this is specified and differs from the value in "kind", an equivalent match and conversion was performed.
|
||||
|
||||
|
||||
For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of
|
||||
`apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`,
|
||||
an API request to apps/v1beta1 deployments would be converted and sent to the webhook
|
||||
with `kind: {group:"apps", version:"v1", kind:"Deployment"}` (matching the rule the webhook registered for),
|
||||
and `requestKind: {group:"apps", version:"v1beta1", kind:"Deployment"}` (indicating the kind of the original API request).
|
||||
|
||||
|
||||
See documentation for the "matchPolicy" field in the webhook configuration type for more details.
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- kind
|
||||
- version
|
||||
type: object
|
||||
requestResource:
|
||||
description: |-
|
||||
RequestResource is the fully-qualified resource of the original API request (for example, v1.pods).
|
||||
If this is specified and differs from the value in "resource", an equivalent match and conversion was performed.
|
||||
|
||||
|
||||
For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of
|
||||
`apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`,
|
||||
an API request to apps/v1beta1 deployments would be converted and sent to the webhook
|
||||
with `resource: {group:"apps", version:"v1", resource:"deployments"}` (matching the resource the webhook registered for),
|
||||
and `requestResource: {group:"apps", version:"v1beta1", resource:"deployments"}` (indicating the resource of the original API request).
|
||||
|
||||
|
||||
See documentation for the "matchPolicy" field in the webhook configuration type.
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
resource:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- resource
|
||||
- version
|
||||
type: object
|
||||
requestSubResource:
|
||||
description: |-
|
||||
RequestSubResource is the name of the subresource of the original API request, if any (for example, "status" or "scale")
|
||||
If this is specified and differs from the value in "subResource", an equivalent match and conversion was performed.
|
||||
See documentation for the "matchPolicy" field in the webhook configuration type.
|
||||
type: string
|
||||
resource:
|
||||
description: Resource is the fully-qualified resource
|
||||
being requested (for example, v1.pods)
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
resource:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- resource
|
||||
- version
|
||||
type: object
|
||||
subResource:
|
||||
description: SubResource is the subresource being requested,
|
||||
if any (for example, "status" or "scale")
|
||||
type: string
|
||||
uid:
|
||||
description: |-
|
||||
UID is an identifier for the individual request/response. It allows us to distinguish instances of requests which are
|
||||
otherwise identical (parallel requests, requests when earlier requests did not modify etc)
|
||||
The UID is meant to track the round trip (request/response) between the KAS and the WebHook, not the user request.
|
||||
It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging.
|
||||
type: string
|
||||
userInfo:
|
||||
description: UserInfo is information about the requesting
|
||||
user
|
||||
properties:
|
||||
extra:
|
||||
additionalProperties:
|
||||
description: ExtraValue masks the value so protobuf
|
||||
can generate
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
description: Any additional information provided by
|
||||
the authenticator.
|
||||
type: object
|
||||
groups:
|
||||
description: The names of groups this user is a part
|
||||
of.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
uid:
|
||||
description: |-
|
||||
A unique value that identifies this user across time. If this user is
|
||||
deleted and another user by the same name is added, they will have
|
||||
different UIDs.
|
||||
type: string
|
||||
username:
|
||||
description: The name that uniquely identifies this
|
||||
user among all active users.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- kind
|
||||
- operation
|
||||
- resource
|
||||
- uid
|
||||
- userInfo
|
||||
type: object
|
||||
operation:
|
||||
description: Operation is the type of resource operation being
|
||||
checked for admission control
|
||||
type: string
|
||||
type: object
|
||||
userInfo:
|
||||
description: RequestInfo contains permission info carried in an
|
||||
admission request.
|
||||
properties:
|
||||
clusterRoles:
|
||||
description: ClusterRoles is a list of possible clusterRoles
|
||||
send the request.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
roles:
|
||||
description: Roles is a list of possible role send the request.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
userInfo:
|
||||
description: UserInfo is the userInfo carried in the admission
|
||||
request.
|
||||
properties:
|
||||
extra:
|
||||
additionalProperties:
|
||||
description: ExtraValue masks the value so protobuf
|
||||
can generate
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
description: Any additional information provided by the
|
||||
authenticator.
|
||||
type: object
|
||||
groups:
|
||||
description: The names of groups this user is a part of.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
uid:
|
||||
description: |-
|
||||
A unique value that identifies this user across time. If this user is
|
||||
deleted and another user by the same name is added, they will have
|
||||
different UIDs.
|
||||
type: string
|
||||
username:
|
||||
description: The name that uniquely identifies this user
|
||||
among all active users.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream needs
|
||||
to be deleted.
|
||||
type: boolean
|
||||
policy:
|
||||
description: Specifies the name of the policy.
|
||||
type: string
|
||||
requestType:
|
||||
description: Type represents request type for background processing
|
||||
enum:
|
||||
- mutate
|
||||
- generate
|
||||
type: string
|
||||
resource:
|
||||
description: ResourceSpec is the information to identify the trigger
|
||||
resource.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
name:
|
||||
description: Name specifies the resource name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
uid:
|
||||
description: UID specifies the resource uid.
|
||||
type: string
|
||||
type: object
|
||||
rule:
|
||||
description: Rule is the associate rule name of the current UR.
|
||||
type: string
|
||||
synchronize:
|
||||
description: |-
|
||||
Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to "false" if not specified.
|
||||
type: boolean
|
||||
required:
|
||||
- context
|
||||
- deleteDownstream
|
||||
- policy
|
||||
- resource
|
||||
- rule
|
||||
type: object
|
||||
status:
|
||||
description: Status contains statistics related to update request.
|
||||
properties:
|
||||
generatedResources:
|
||||
description: |-
|
||||
This will track the resources that are updated by the generate Policy.
|
||||
Will be used during clean up resources.
|
||||
items:
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
name:
|
||||
description: Name specifies the resource name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
uid:
|
||||
description: UID specifies the resource uid.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
handler:
|
||||
description: Deprecated
|
||||
type: string
|
||||
message:
|
||||
description: Specifies request status message.
|
||||
type: string
|
||||
retryCount:
|
||||
type: integer
|
||||
state:
|
||||
description: State represents state of the update request.
|
||||
type: string
|
||||
required:
|
||||
- state
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: false
|
||||
subresources:
|
||||
status: {}
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.policy
|
||||
name: Policy
|
||||
|
@ -453,7 +67,9 @@ spec:
|
|||
description: ResourceSpec is the information to identify the trigger resource.
|
||||
properties:
|
||||
context:
|
||||
description: Context ...
|
||||
description: |-
|
||||
Context represents admission request context.
|
||||
It is used upon admission review only and is shared across rules within the same UR.
|
||||
properties:
|
||||
admissionRequestInfo:
|
||||
description: AdmissionRequestInfoObject stores the admission request
|
||||
|
@ -694,8 +310,9 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream needs
|
||||
to be deleted.
|
||||
description: |-
|
||||
DeleteDownstream represents whether the downstream needs to be deleted.
|
||||
Deprecated
|
||||
type: boolean
|
||||
policy:
|
||||
description: Specifies the name of the policy.
|
||||
|
@ -729,10 +346,56 @@ spec:
|
|||
rule:
|
||||
description: Rule is the associate rule name of the current UR.
|
||||
type: string
|
||||
ruleContext:
|
||||
description: |-
|
||||
RuleContext is the associate context to apply rules.
|
||||
optional
|
||||
items:
|
||||
properties:
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream
|
||||
needs to be deleted.
|
||||
type: boolean
|
||||
rule:
|
||||
description: Rule is the associate rule name of the current
|
||||
UR.
|
||||
type: string
|
||||
synchronize:
|
||||
description: |-
|
||||
Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to "false" if not specified.
|
||||
type: boolean
|
||||
trigger:
|
||||
description: ResourceSpec is the information to identify the
|
||||
trigger resource.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
name:
|
||||
description: Name specifies the resource name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
uid:
|
||||
description: UID specifies the resource uid.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- deleteDownstream
|
||||
- rule
|
||||
- trigger
|
||||
type: object
|
||||
type: array
|
||||
synchronize:
|
||||
description: |-
|
||||
Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to "false" if not specified.
|
||||
Deprecated, will be removed in 1.14.
|
||||
type: boolean
|
||||
required:
|
||||
- context
|
||||
|
|
|
@ -41380,392 +41380,6 @@ spec:
|
|||
singular: updaterequest
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.policy
|
||||
name: Policy
|
||||
type: string
|
||||
- jsonPath: .spec.rule
|
||||
name: Rule
|
||||
type: string
|
||||
- jsonPath: .spec.requestType
|
||||
name: RuleType
|
||||
type: string
|
||||
- jsonPath: .spec.resource.kind
|
||||
name: ResourceKind
|
||||
type: string
|
||||
- jsonPath: .spec.resource.name
|
||||
name: ResourceName
|
||||
type: string
|
||||
- jsonPath: .spec.resource.namespace
|
||||
name: ResourceNamespace
|
||||
type: string
|
||||
- jsonPath: .status.state
|
||||
name: status
|
||||
type: string
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
deprecated: true
|
||||
name: v1beta1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: UpdateRequest is a request to process mutate and generate rules
|
||||
in background.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ResourceSpec is the information to identify the trigger resource.
|
||||
properties:
|
||||
context:
|
||||
description: Context ...
|
||||
properties:
|
||||
admissionRequestInfo:
|
||||
description: AdmissionRequestInfoObject stores the admission request
|
||||
and operation details
|
||||
properties:
|
||||
admissionRequest:
|
||||
description: AdmissionRequest describes the admission.Attributes
|
||||
for the admission request.
|
||||
properties:
|
||||
dryRun:
|
||||
description: |-
|
||||
DryRun indicates that modifications will definitely not be persisted for this request.
|
||||
Defaults to false.
|
||||
type: boolean
|
||||
kind:
|
||||
description: Kind is the fully-qualified type of object
|
||||
being submitted (for example, v1.Pod or autoscaling.v1.Scale)
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- kind
|
||||
- version
|
||||
type: object
|
||||
name:
|
||||
description: |-
|
||||
Name is the name of the object as presented in the request. On a CREATE operation, the client may omit name and
|
||||
rely on the server to generate the name. If that is the case, this field will contain an empty string.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the namespace associated with
|
||||
the request (if any).
|
||||
type: string
|
||||
object:
|
||||
description: Object is the object from the incoming request.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
oldObject:
|
||||
description: OldObject is the existing object. Only populated
|
||||
for DELETE and UPDATE requests.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
operation:
|
||||
description: |-
|
||||
Operation is the operation being performed. This may be different than the operation
|
||||
requested. e.g. a patch can result in either a CREATE or UPDATE Operation.
|
||||
type: string
|
||||
options:
|
||||
description: |-
|
||||
Options is the operation option structure of the operation being performed.
|
||||
e.g. `meta.k8s.io/v1.DeleteOptions` or `meta.k8s.io/v1.CreateOptions`. This may be
|
||||
different than the options the caller provided. e.g. for a patch request the performed
|
||||
Operation might be a CREATE, in which case the Options will a
|
||||
`meta.k8s.io/v1.CreateOptions` even though the caller provided `meta.k8s.io/v1.PatchOptions`.
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
requestKind:
|
||||
description: |-
|
||||
RequestKind is the fully-qualified type of the original API request (for example, v1.Pod or autoscaling.v1.Scale).
|
||||
If this is specified and differs from the value in "kind", an equivalent match and conversion was performed.
|
||||
|
||||
|
||||
For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of
|
||||
`apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`,
|
||||
an API request to apps/v1beta1 deployments would be converted and sent to the webhook
|
||||
with `kind: {group:"apps", version:"v1", kind:"Deployment"}` (matching the rule the webhook registered for),
|
||||
and `requestKind: {group:"apps", version:"v1beta1", kind:"Deployment"}` (indicating the kind of the original API request).
|
||||
|
||||
|
||||
See documentation for the "matchPolicy" field in the webhook configuration type for more details.
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- kind
|
||||
- version
|
||||
type: object
|
||||
requestResource:
|
||||
description: |-
|
||||
RequestResource is the fully-qualified resource of the original API request (for example, v1.pods).
|
||||
If this is specified and differs from the value in "resource", an equivalent match and conversion was performed.
|
||||
|
||||
|
||||
For example, if deployments can be modified via apps/v1 and apps/v1beta1, and a webhook registered a rule of
|
||||
`apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]` and `matchPolicy: Equivalent`,
|
||||
an API request to apps/v1beta1 deployments would be converted and sent to the webhook
|
||||
with `resource: {group:"apps", version:"v1", resource:"deployments"}` (matching the resource the webhook registered for),
|
||||
and `requestResource: {group:"apps", version:"v1beta1", resource:"deployments"}` (indicating the resource of the original API request).
|
||||
|
||||
|
||||
See documentation for the "matchPolicy" field in the webhook configuration type.
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
resource:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- resource
|
||||
- version
|
||||
type: object
|
||||
requestSubResource:
|
||||
description: |-
|
||||
RequestSubResource is the name of the subresource of the original API request, if any (for example, "status" or "scale")
|
||||
If this is specified and differs from the value in "subResource", an equivalent match and conversion was performed.
|
||||
See documentation for the "matchPolicy" field in the webhook configuration type.
|
||||
type: string
|
||||
resource:
|
||||
description: Resource is the fully-qualified resource
|
||||
being requested (for example, v1.pods)
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
resource:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
required:
|
||||
- group
|
||||
- resource
|
||||
- version
|
||||
type: object
|
||||
subResource:
|
||||
description: SubResource is the subresource being requested,
|
||||
if any (for example, "status" or "scale")
|
||||
type: string
|
||||
uid:
|
||||
description: |-
|
||||
UID is an identifier for the individual request/response. It allows us to distinguish instances of requests which are
|
||||
otherwise identical (parallel requests, requests when earlier requests did not modify etc)
|
||||
The UID is meant to track the round trip (request/response) between the KAS and the WebHook, not the user request.
|
||||
It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging.
|
||||
type: string
|
||||
userInfo:
|
||||
description: UserInfo is information about the requesting
|
||||
user
|
||||
properties:
|
||||
extra:
|
||||
additionalProperties:
|
||||
description: ExtraValue masks the value so protobuf
|
||||
can generate
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
description: Any additional information provided by
|
||||
the authenticator.
|
||||
type: object
|
||||
groups:
|
||||
description: The names of groups this user is a part
|
||||
of.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
uid:
|
||||
description: |-
|
||||
A unique value that identifies this user across time. If this user is
|
||||
deleted and another user by the same name is added, they will have
|
||||
different UIDs.
|
||||
type: string
|
||||
username:
|
||||
description: The name that uniquely identifies this
|
||||
user among all active users.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- kind
|
||||
- operation
|
||||
- resource
|
||||
- uid
|
||||
- userInfo
|
||||
type: object
|
||||
operation:
|
||||
description: Operation is the type of resource operation being
|
||||
checked for admission control
|
||||
type: string
|
||||
type: object
|
||||
userInfo:
|
||||
description: RequestInfo contains permission info carried in an
|
||||
admission request.
|
||||
properties:
|
||||
clusterRoles:
|
||||
description: ClusterRoles is a list of possible clusterRoles
|
||||
send the request.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
roles:
|
||||
description: Roles is a list of possible role send the request.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
userInfo:
|
||||
description: UserInfo is the userInfo carried in the admission
|
||||
request.
|
||||
properties:
|
||||
extra:
|
||||
additionalProperties:
|
||||
description: ExtraValue masks the value so protobuf
|
||||
can generate
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
description: Any additional information provided by the
|
||||
authenticator.
|
||||
type: object
|
||||
groups:
|
||||
description: The names of groups this user is a part of.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
uid:
|
||||
description: |-
|
||||
A unique value that identifies this user across time. If this user is
|
||||
deleted and another user by the same name is added, they will have
|
||||
different UIDs.
|
||||
type: string
|
||||
username:
|
||||
description: The name that uniquely identifies this user
|
||||
among all active users.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream needs
|
||||
to be deleted.
|
||||
type: boolean
|
||||
policy:
|
||||
description: Specifies the name of the policy.
|
||||
type: string
|
||||
requestType:
|
||||
description: Type represents request type for background processing
|
||||
enum:
|
||||
- mutate
|
||||
- generate
|
||||
type: string
|
||||
resource:
|
||||
description: ResourceSpec is the information to identify the trigger
|
||||
resource.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
name:
|
||||
description: Name specifies the resource name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
uid:
|
||||
description: UID specifies the resource uid.
|
||||
type: string
|
||||
type: object
|
||||
rule:
|
||||
description: Rule is the associate rule name of the current UR.
|
||||
type: string
|
||||
synchronize:
|
||||
description: |-
|
||||
Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to "false" if not specified.
|
||||
type: boolean
|
||||
required:
|
||||
- context
|
||||
- deleteDownstream
|
||||
- policy
|
||||
- resource
|
||||
- rule
|
||||
type: object
|
||||
status:
|
||||
description: Status contains statistics related to update request.
|
||||
properties:
|
||||
generatedResources:
|
||||
description: |-
|
||||
This will track the resources that are updated by the generate Policy.
|
||||
Will be used during clean up resources.
|
||||
items:
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
name:
|
||||
description: Name specifies the resource name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
uid:
|
||||
description: UID specifies the resource uid.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
handler:
|
||||
description: Deprecated
|
||||
type: string
|
||||
message:
|
||||
description: Specifies request status message.
|
||||
type: string
|
||||
retryCount:
|
||||
type: integer
|
||||
state:
|
||||
description: State represents state of the update request.
|
||||
type: string
|
||||
required:
|
||||
- state
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: false
|
||||
subresources:
|
||||
status: {}
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.policy
|
||||
name: Policy
|
||||
|
@ -41815,7 +41429,9 @@ spec:
|
|||
description: ResourceSpec is the information to identify the trigger resource.
|
||||
properties:
|
||||
context:
|
||||
description: Context ...
|
||||
description: |-
|
||||
Context represents admission request context.
|
||||
It is used upon admission review only and is shared across rules within the same UR.
|
||||
properties:
|
||||
admissionRequestInfo:
|
||||
description: AdmissionRequestInfoObject stores the admission request
|
||||
|
@ -42056,8 +41672,9 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream needs
|
||||
to be deleted.
|
||||
description: |-
|
||||
DeleteDownstream represents whether the downstream needs to be deleted.
|
||||
Deprecated
|
||||
type: boolean
|
||||
policy:
|
||||
description: Specifies the name of the policy.
|
||||
|
@ -42091,10 +41708,56 @@ spec:
|
|||
rule:
|
||||
description: Rule is the associate rule name of the current UR.
|
||||
type: string
|
||||
ruleContext:
|
||||
description: |-
|
||||
RuleContext is the associate context to apply rules.
|
||||
optional
|
||||
items:
|
||||
properties:
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream
|
||||
needs to be deleted.
|
||||
type: boolean
|
||||
rule:
|
||||
description: Rule is the associate rule name of the current
|
||||
UR.
|
||||
type: string
|
||||
synchronize:
|
||||
description: |-
|
||||
Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to "false" if not specified.
|
||||
type: boolean
|
||||
trigger:
|
||||
description: ResourceSpec is the information to identify the
|
||||
trigger resource.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
name:
|
||||
description: Name specifies the resource name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
uid:
|
||||
description: UID specifies the resource uid.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- deleteDownstream
|
||||
- rule
|
||||
- trigger
|
||||
type: object
|
||||
type: array
|
||||
synchronize:
|
||||
description: |-
|
||||
Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to "false" if not specified.
|
||||
Deprecated, will be removed in 1.14.
|
||||
type: boolean
|
||||
required:
|
||||
- context
|
||||
|
|
|
@ -3559,6 +3559,7 @@ ResourceDescription
|
|||
<a href="#kyverno.io/v1.TargetResourceSpec">TargetResourceSpec</a>,
|
||||
<a href="#kyverno.io/v1beta1.UpdateRequestSpec">UpdateRequestSpec</a>,
|
||||
<a href="#kyverno.io/v1beta1.UpdateRequestStatus">UpdateRequestStatus</a>,
|
||||
<a href="#kyverno.io/v2.RuleContext">RuleContext</a>,
|
||||
<a href="#kyverno.io/v2.UpdateRequestSpec">UpdateRequestSpec</a>,
|
||||
<a href="#kyverno.io/v2.UpdateRequestStatus">UpdateRequestStatus</a>)
|
||||
</p>
|
||||
|
@ -5877,6 +5878,20 @@ string
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>ruleContext</code><br/>
|
||||
<em>
|
||||
<a href="#kyverno.io/v2.RuleContext">
|
||||
[]RuleContext
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>RuleContext is the associate context to apply rules.
|
||||
optional</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>rule</code><br/>
|
||||
<em>
|
||||
string
|
||||
|
@ -5894,7 +5909,8 @@ bool
|
|||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>DeleteDownstream represents whether the downstream needs to be deleted.</p>
|
||||
<p>DeleteDownstream represents whether the downstream needs to be deleted.
|
||||
Deprecated</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -5906,7 +5922,8 @@ bool
|
|||
</td>
|
||||
<td>
|
||||
<p>Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to “false” if not specified.</p>
|
||||
Optional. Defaults to “false” if not specified.
|
||||
Deprecated, will be removed in 1.14.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -5932,7 +5949,8 @@ UpdateRequestSpecContext
|
|||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Context …</p>
|
||||
<p>Context represents admission request context.
|
||||
It is used upon admission review only and is shared across rules within the same UR.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -6475,6 +6493,72 @@ Kubernetes authentication/v1.UserInfo
|
|||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<h3 id="kyverno.io/v2.RuleContext">RuleContext
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kyverno.io/v2.UpdateRequestSpec">UpdateRequestSpec</a>)
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>rule</code><br/>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Rule is the associate rule name of the current UR.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>deleteDownstream</code><br/>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>DeleteDownstream represents whether the downstream needs to be deleted.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>synchronize</code><br/>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to “false” if not specified.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>trigger</code><br/>
|
||||
<em>
|
||||
<a href="#kyverno.io/v1.ResourceSpec">
|
||||
ResourceSpec
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>ResourceSpec is the information to identify the trigger resource.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v2.UpdateRequestSpec">UpdateRequestSpec
|
||||
</h3>
|
||||
<p>
|
||||
|
@ -6518,6 +6602,20 @@ string
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>ruleContext</code><br/>
|
||||
<em>
|
||||
<a href="#kyverno.io/v2.RuleContext">
|
||||
[]RuleContext
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>RuleContext is the associate context to apply rules.
|
||||
optional</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>rule</code><br/>
|
||||
<em>
|
||||
string
|
||||
|
@ -6535,7 +6633,8 @@ bool
|
|||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>DeleteDownstream represents whether the downstream needs to be deleted.</p>
|
||||
<p>DeleteDownstream represents whether the downstream needs to be deleted.
|
||||
Deprecated</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -6547,7 +6646,8 @@ bool
|
|||
</td>
|
||||
<td>
|
||||
<p>Synchronize represents the sync behavior of the corresponding rule
|
||||
Optional. Defaults to “false” if not specified.</p>
|
||||
Optional. Defaults to “false” if not specified.
|
||||
Deprecated, will be removed in 1.14.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -6573,7 +6673,8 @@ UpdateRequestSpecContext
|
|||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Context …</p>
|
||||
<p>Context represents admission request context.
|
||||
It is used upon admission review only and is shared across rules within the same UR.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
func NewBackgroundContext(
|
||||
logger logr.Logger,
|
||||
dclient dclient.Interface,
|
||||
ur *kyvernov2.UpdateRequest,
|
||||
urContext kyvernov2.UpdateRequestSpecContext,
|
||||
policy kyvernov1.PolicyInterface,
|
||||
trigger *unstructured.Unstructured,
|
||||
cfg config.Configuration,
|
||||
|
@ -27,15 +27,15 @@ func NewBackgroundContext(
|
|||
var new, old unstructured.Unstructured
|
||||
var err error
|
||||
|
||||
if ur.Spec.Context.AdmissionRequestInfo.AdmissionRequest != nil {
|
||||
new, old, err = admissionutils.ExtractResources(nil, *ur.Spec.Context.AdmissionRequestInfo.AdmissionRequest)
|
||||
if urContext.AdmissionRequestInfo.AdmissionRequest != nil {
|
||||
new, old, err = admissionutils.ExtractResources(nil, *urContext.AdmissionRequestInfo.AdmissionRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load request in context: %w", err)
|
||||
}
|
||||
if new.Object != nil {
|
||||
if !check(&new, trigger) {
|
||||
err := fmt.Errorf("resources don't match")
|
||||
return nil, fmt.Errorf("resource %v: %w", ur.Spec.GetResource().String(), err)
|
||||
return nil, fmt.Errorf("resources don't match, want: %v/%v, got: %v/%v",
|
||||
trigger.GetNamespace(), trigger.GetName(), new.GetNamespace(), new.GetName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,19 +47,19 @@ func NewBackgroundContext(
|
|||
}
|
||||
|
||||
var policyContext *engine.PolicyContext
|
||||
if ur.Spec.Context.AdmissionRequestInfo.AdmissionRequest == nil {
|
||||
if urContext.AdmissionRequestInfo.AdmissionRequest == nil {
|
||||
policyContext, err = engine.NewPolicyContext(
|
||||
jp,
|
||||
*trigger,
|
||||
kyvernov1.AdmissionOperation(ur.Spec.Context.AdmissionRequestInfo.Operation),
|
||||
&ur.Spec.Context.UserRequestInfo,
|
||||
kyvernov1.AdmissionOperation(urContext.AdmissionRequestInfo.Operation),
|
||||
&urContext.UserRequestInfo,
|
||||
cfg,
|
||||
)
|
||||
} else {
|
||||
policyContext, err = engine.NewPolicyContextFromAdmissionRequest(
|
||||
jp,
|
||||
*ur.Spec.Context.AdmissionRequestInfo.AdmissionRequest,
|
||||
ur.Spec.Context.UserRequestInfo,
|
||||
*urContext.AdmissionRequestInfo.AdmissionRequest,
|
||||
urContext.UserRequestInfo,
|
||||
trigger.GroupVersionKind(),
|
||||
cfg,
|
||||
)
|
||||
|
|
|
@ -53,18 +53,12 @@ func MutateLabelsSet(policyKey string, trigger Object) pkglabels.Set {
|
|||
return set
|
||||
}
|
||||
|
||||
func GenerateLabelsSet(policyKey string, trigger Object) pkglabels.Set {
|
||||
func GenerateLabelsSet(policyKey string) pkglabels.Set {
|
||||
_, policyName, _ := cache.SplitMetaNamespaceKey(policyKey)
|
||||
|
||||
set := pkglabels.Set{
|
||||
kyvernov2.URGeneratePolicyLabel: policyName,
|
||||
}
|
||||
isNil := trigger == nil || (reflect.ValueOf(trigger).Kind() == reflect.Ptr && reflect.ValueOf(trigger).IsNil())
|
||||
if !isNil {
|
||||
set[kyvernov2.URGenerateResourceUIDLabel] = string(trigger.GetUID())
|
||||
set[kyvernov2.URGenerateResourceNSLabel] = trigger.GetNamespace()
|
||||
set[kyvernov2.URGenerateResourceKindLabel] = trigger.GetKind()
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,10 @@ package common
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
|
@ -13,10 +15,13 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func GetResource(client dclient.Interface, urSpec kyvernov2.UpdateRequestSpec, log logr.Logger) (resource *unstructured.Unstructured, err error) {
|
||||
resourceSpec := urSpec.GetResource()
|
||||
func GetResource(client dclient.Interface, resourceSpec kyvernov1.ResourceSpec, urSpec kyvernov2.UpdateRequestSpec, log logr.Logger) (resource *unstructured.Unstructured, err error) {
|
||||
obj := resourceSpec
|
||||
if reflect.DeepEqual(obj, kyvernov1.ResourceSpec{}) {
|
||||
obj = urSpec.GetResource()
|
||||
}
|
||||
|
||||
if urSpec.GetResource().GetUID() != "" {
|
||||
if obj.GetUID() != "" {
|
||||
triggers, err := client.ListResource(context.TODO(), resourceSpec.GetAPIVersion(), resourceSpec.GetKind(), resourceSpec.GetNamespace(), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list trigger resources: %v", err)
|
||||
|
@ -27,7 +32,7 @@ func GetResource(client dclient.Interface, urSpec kyvernov2.UpdateRequestSpec, l
|
|||
return &trigger, nil
|
||||
}
|
||||
}
|
||||
} else if urSpec.GetResource().GetName() != "" {
|
||||
} else if obj.GetName() != "" {
|
||||
if resourceSpec.Kind == "Namespace" {
|
||||
resourceSpec.Namespace = ""
|
||||
}
|
||||
|
@ -44,7 +49,7 @@ func GetResource(client dclient.Interface, urSpec kyvernov2.UpdateRequestSpec, l
|
|||
return resource, nil
|
||||
}
|
||||
|
||||
if resource == nil && urSpec.Context.AdmissionRequestInfo.AdmissionRequest != nil {
|
||||
if urSpec.Context.AdmissionRequestInfo.AdmissionRequest != nil {
|
||||
request := urSpec.Context.AdmissionRequestInfo.AdmissionRequest
|
||||
raw := request.Object.Raw
|
||||
if request.Operation == admissionv1.Delete {
|
||||
|
@ -52,8 +57,12 @@ func GetResource(client dclient.Interface, urSpec kyvernov2.UpdateRequestSpec, l
|
|||
}
|
||||
|
||||
resource, err = kubeutils.BytesToUnstructured(raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert raw object to unstructured: %v", err)
|
||||
} else {
|
||||
return resource, nil
|
||||
}
|
||||
}
|
||||
|
||||
log.V(3).Info("fetched trigger resource", "resourceSpec", resourceSpec)
|
||||
return resource, err
|
||||
return nil, fmt.Errorf("resource not found")
|
||||
}
|
||||
|
|
|
@ -14,14 +14,10 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func (c *GenerateController) deleteDownstream(policy kyvernov1.PolicyInterface, ur *kyvernov2.UpdateRequest) (err error) {
|
||||
if !ur.Spec.DeleteDownstream {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *GenerateController) deleteDownstream(policy kyvernov1.PolicyInterface, ruleContext kyvernov2.RuleContext, ur *kyvernov2.UpdateRequest) (err error) {
|
||||
// handle data policy/rule deletion
|
||||
if ur.Status.GeneratedResources != nil {
|
||||
c.log.V(4).Info("policy/rule no longer exists, deleting the downstream resource based on synchronize", "ur", ur.Name, "policy", ur.Spec.Policy, "rule", ur.Spec.Rule)
|
||||
c.log.V(4).Info("policy/rule no longer exists, deleting the downstream resource based on synchronize", "ur", ur.Name, "policy", ur.Spec.Policy)
|
||||
var errs []error
|
||||
failedDownstreams := []kyvernov1.ResourceSpec{}
|
||||
for _, e := range ur.Status.GeneratedResources {
|
||||
|
@ -46,18 +42,17 @@ func (c *GenerateController) deleteDownstream(policy kyvernov1.PolicyInterface,
|
|||
return nil
|
||||
}
|
||||
|
||||
return c.handleNonPolicyChanges(policy, ur)
|
||||
return c.handleNonPolicyChanges(policy, ruleContext, ur)
|
||||
}
|
||||
|
||||
func (c *GenerateController) handleNonPolicyChanges(policy kyvernov1.PolicyInterface, ur *kyvernov2.UpdateRequest) error {
|
||||
if !ur.Spec.DeleteDownstream {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *GenerateController) handleNonPolicyChanges(policy kyvernov1.PolicyInterface, ruleContext kyvernov2.RuleContext, ur *kyvernov2.UpdateRequest) error {
|
||||
logger := c.log.V(4).WithValues("ur", ur.Name, "policy", ur.Spec.Policy, "rule", ruleContext.Rule)
|
||||
logger.Info("synchronize for none-policy changes")
|
||||
for _, rule := range policy.GetSpec().Rules {
|
||||
if ur.Spec.Rule != rule.Name {
|
||||
if ruleContext.Rule != rule.Name {
|
||||
continue
|
||||
}
|
||||
logger.Info("deleting the downstream resource based on synchronize")
|
||||
labels := map[string]string{
|
||||
common.GeneratePolicyLabel: policy.GetName(),
|
||||
common.GeneratePolicyNamespaceLabel: policy.GetNamespace(),
|
||||
|
@ -65,7 +60,7 @@ func (c *GenerateController) handleNonPolicyChanges(policy kyvernov1.PolicyInter
|
|||
kyverno.LabelAppManagedBy: kyverno.ValueKyvernoApp,
|
||||
}
|
||||
|
||||
downstreams, err := c.getDownstreams(rule, labels, ur)
|
||||
downstreams, err := c.getDownstreams(rule, labels, &ruleContext)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch downstream resources: %v", err)
|
||||
}
|
||||
|
@ -77,7 +72,7 @@ func (c *GenerateController) handleNonPolicyChanges(policy kyvernov1.PolicyInter
|
|||
failedDownstreams = append(failedDownstreams, spec)
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
c.log.V(4).Info("downstream resource deleted", "spec", spec.String())
|
||||
logger.Info("downstream resource deleted", "spec", spec.String())
|
||||
}
|
||||
}
|
||||
if len(errs) != 0 {
|
||||
|
@ -88,22 +83,22 @@ func (c *GenerateController) handleNonPolicyChanges(policy kyvernov1.PolicyInter
|
|||
_, err = c.statusControl.Success(ur.GetName(), nil)
|
||||
}
|
||||
if err != nil {
|
||||
c.log.Error(err, "failed to update ur status")
|
||||
logger.Error(err, "failed to update ur status")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *GenerateController) getDownstreams(rule kyvernov1.Rule, selector map[string]string, ur *kyvernov2.UpdateRequest) (*unstructured.UnstructuredList, error) {
|
||||
gv, err := ur.Spec.GetResource().GetGroupVersion()
|
||||
func (c *GenerateController) getDownstreams(rule kyvernov1.Rule, selector map[string]string, ruleContext *kyvernov2.RuleContext) (*unstructured.UnstructuredList, error) {
|
||||
gv, err := ruleContext.Trigger.GetGroupVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
selector[common.GenerateTriggerUIDLabel] = string(ur.Spec.GetResource().GetUID())
|
||||
selector[common.GenerateTriggerNSLabel] = ur.Spec.GetResource().GetNamespace()
|
||||
selector[common.GenerateTriggerKindLabel] = ur.Spec.GetResource().GetKind()
|
||||
selector[common.GenerateTriggerUIDLabel] = string(ruleContext.Trigger.GetUID())
|
||||
selector[common.GenerateTriggerNSLabel] = ruleContext.Trigger.GetNamespace()
|
||||
selector[common.GenerateTriggerKindLabel] = ruleContext.Trigger.GetKind()
|
||||
selector[common.GenerateTriggerGroupLabel] = gv.Group
|
||||
selector[common.GenerateTriggerVersionLabel] = gv.Version
|
||||
if rule.Generation.GetKind() != "" {
|
||||
|
@ -117,7 +112,7 @@ func (c *GenerateController) getDownstreams(rule kyvernov1.Rule, selector map[st
|
|||
if len(downstreamList.Items) == 0 {
|
||||
// Fetch downstream resources using the trigger name label
|
||||
delete(selector, common.GenerateTriggerUIDLabel)
|
||||
selector[common.GenerateTriggerNameLabel] = ur.Spec.GetResource().GetName()
|
||||
selector[common.GenerateTriggerNameLabel] = ruleContext.Trigger.GetName()
|
||||
c.log.V(4).Info("fetching downstream resource by the name", "APIVersion", rule.Generation.GetAPIVersion(), "kind", rule.Generation.GetKind(), "selector", selector)
|
||||
dsList, err := common.FindDownstream(c.client, rule.Generation.GetAPIVersion(), rule.Generation.GetKind(), selector)
|
||||
if err != nil {
|
||||
|
@ -140,7 +135,7 @@ func (c *GenerateController) getDownstreams(rule kyvernov1.Rule, selector map[st
|
|||
|
||||
if len(dsList.Items) == 0 {
|
||||
delete(selector, common.GenerateTriggerUIDLabel)
|
||||
selector[common.GenerateTriggerNameLabel] = ur.Spec.GetResource().GetName()
|
||||
selector[common.GenerateTriggerNameLabel] = ruleContext.Trigger.GetName()
|
||||
c.log.V(4).Info("fetching downstream resource by the name", "APIVersion", rule.Generation.GetAPIVersion(), "kind", rule.Generation.GetKind(), "selector", selector)
|
||||
dsList, err = common.FindDownstream(c.client, rule.Generation.GetAPIVersion(), rule.Generation.GetKind(), selector)
|
||||
if err != nil {
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
|
@ -14,7 +13,7 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func manageClone(log logr.Logger, target, sourceSpec kyvernov1.ResourceSpec, policy kyvernov1.PolicyInterface, ur kyvernov2.UpdateRequest, rule kyvernov1.Rule, client dclient.Interface) generateResponse {
|
||||
func manageClone(log logr.Logger, target, sourceSpec kyvernov1.ResourceSpec, policy kyvernov1.PolicyInterface, rule kyvernov1.Rule, client dclient.Interface) generateResponse {
|
||||
source := sourceSpec
|
||||
clone := rule.Generation
|
||||
if clone.Clone.Name != "" {
|
||||
|
@ -60,15 +59,9 @@ func manageClone(log logr.Logger, target, sourceSpec kyvernov1.ResourceSpec, pol
|
|||
sourceObjCopy.SetResourceVersion("")
|
||||
|
||||
targetObj, err := client.GetResource(context.TODO(), target.GetAPIVersion(), target.GetKind(), target.GetNamespace(), target.GetName())
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) && len(ur.Status.GeneratedResources) != 0 && !clone.Synchronize {
|
||||
log.V(4).Info("synchronization is disabled, recreation will be skipped", "target resource", targetObj)
|
||||
return newSkipGenerateResponse(nil, target, nil)
|
||||
}
|
||||
if apierrors.IsNotFound(err) {
|
||||
return newCreateGenerateResponse(sourceObjCopy.UnstructuredContent(), target, nil)
|
||||
}
|
||||
return newSkipGenerateResponse(nil, target, fmt.Errorf("failed to get the target source: %v", err))
|
||||
if err != nil && apierrors.IsNotFound(err) {
|
||||
// the target resource should always exist regardless of synchronize settings
|
||||
return newCreateGenerateResponse(sourceObjCopy.UnstructuredContent(), target, nil)
|
||||
}
|
||||
|
||||
if targetObj != nil {
|
||||
|
@ -88,7 +81,7 @@ func manageClone(log logr.Logger, target, sourceSpec kyvernov1.ResourceSpec, pol
|
|||
return newCreateGenerateResponse(sourceObjCopy.UnstructuredContent(), target, nil)
|
||||
}
|
||||
|
||||
func manageCloneList(log logr.Logger, targetNamespace string, ur kyvernov2.UpdateRequest, policy kyvernov1.PolicyInterface, rule kyvernov1.Rule, client dclient.Interface) []generateResponse {
|
||||
func manageCloneList(log logr.Logger, targetNamespace string, policy kyvernov1.PolicyInterface, rule kyvernov1.Rule, client dclient.Interface) []generateResponse {
|
||||
var responses []generateResponse
|
||||
cloneList := rule.Generation.CloneList
|
||||
sourceNamespace := cloneList.Namespace
|
||||
|
@ -109,7 +102,7 @@ func manageCloneList(log logr.Logger, targetNamespace string, ur kyvernov2.Updat
|
|||
for _, source := range sources.Items {
|
||||
target := newResourceSpec(source.GetAPIVersion(), source.GetKind(), targetNamespace, source.GetName())
|
||||
responses = append(responses,
|
||||
manageClone(log, target, newResourceSpec(source.GetAPIVersion(), source.GetKind(), source.GetNamespace(), source.GetName()), policy, ur, rule, client))
|
||||
manageClone(log, target, newResourceSpec(source.GetAPIVersion(), source.GetKind(), source.GetNamespace(), source.GetName()), policy, rule, client))
|
||||
}
|
||||
}
|
||||
return responses
|
||||
|
|
|
@ -2,18 +2,16 @@ package generate
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func manageData(log logr.Logger, target kyvernov1.ResourceSpec, data interface{}, synchronize bool, ur kyvernov2.UpdateRequest, client dclient.Interface) generateResponse {
|
||||
func manageData(log logr.Logger, target kyvernov1.ResourceSpec, data interface{}, synchronize bool, client dclient.Interface) generateResponse {
|
||||
if data == nil {
|
||||
log.V(4).Info("data is nil - skipping update")
|
||||
return newSkipGenerateResponse(nil, target, nil)
|
||||
|
@ -25,16 +23,9 @@ func manageData(log logr.Logger, target kyvernov1.ResourceSpec, data interface{}
|
|||
}
|
||||
|
||||
targetObj, err := client.GetResource(context.TODO(), target.GetAPIVersion(), target.GetKind(), target.GetNamespace(), target.GetName())
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) && len(ur.Status.GeneratedResources) != 0 && !synchronize {
|
||||
log.V(4).Info("synchronize is disable - skip re-create")
|
||||
return newSkipGenerateResponse(nil, target, nil)
|
||||
}
|
||||
if apierrors.IsNotFound(err) {
|
||||
return newCreateGenerateResponse(resource, target, nil)
|
||||
}
|
||||
|
||||
return newSkipGenerateResponse(nil, target, fmt.Errorf("failed to get the target source: %v", err))
|
||||
if err != nil && apierrors.IsNotFound(err) {
|
||||
// the target resource should always exist regardless of synchronize settings
|
||||
return newCreateGenerateResponse(resource, target, nil)
|
||||
}
|
||||
|
||||
log.V(4).Info("found target resource")
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
||||
"github.com/kyverno/kyverno/pkg/engine/validate"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
|
@ -31,13 +30,11 @@ import (
|
|||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
validationpolicy "github.com/kyverno/kyverno/pkg/validation/policy"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/multierr"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
corev1listers "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
@ -95,58 +92,56 @@ func NewGenerateController(
|
|||
}
|
||||
|
||||
func (c *GenerateController) ProcessUR(ur *kyvernov2.UpdateRequest) error {
|
||||
logger := c.log.WithValues("name", ur.GetName(), "policy", ur.Spec.GetPolicyKey(), "rule", ur.Spec.GetRuleName(), "resource", ur.Spec.GetResource().String())
|
||||
var err error
|
||||
logger := c.log.WithValues("name", ur.GetName(), "policy", ur.Spec.GetPolicyKey())
|
||||
var genResources []kyvernov1.ResourceSpec
|
||||
logger.Info("start processing UR", "ur", ur.Name, "resourceVersion", ur.GetResourceVersion())
|
||||
|
||||
trigger, err := c.getTrigger(ur.Spec)
|
||||
if err != nil || trigger == nil {
|
||||
logger.V(3).Info("the trigger resource does not exist or is pending creation")
|
||||
if err := updateStatus(c.statusControl, *ur, err, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(trigger.GetKind(), trigger.GetNamespace(), c.nsLister, logger)
|
||||
genResources, err = c.applyGenerate(*trigger, *ur, namespaceLabels)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), doesNotApply) {
|
||||
ur.Status.State = kyvernov2.Completed
|
||||
logger.V(4).Info(fmt.Sprintf("%s, updating UR status to Completed", err.Error()))
|
||||
_, err := c.kyvernoClient.KyvernoV2().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), ur, metav1.UpdateOptions{})
|
||||
return err
|
||||
var failures []error
|
||||
for i := 0; i < len(ur.Spec.RuleContext); i++ {
|
||||
rule := ur.Spec.RuleContext[i]
|
||||
trigger, err := c.getTrigger(ur.Spec, i)
|
||||
if err != nil || trigger == nil {
|
||||
logger.V(4).Info("the trigger resource does not exist or is pending creation")
|
||||
failures = append(failures, fmt.Errorf("rule %s failed: failed to fetch trigger resource: %v", rule.Rule, err))
|
||||
continue
|
||||
}
|
||||
|
||||
policy, err := c.getPolicySpec(*ur)
|
||||
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(trigger.GetKind(), trigger.GetNamespace(), c.nsLister, logger)
|
||||
genResources, err = c.applyGenerate(*trigger, *ur, i, namespaceLabels)
|
||||
if err != nil {
|
||||
return err
|
||||
if strings.Contains(err.Error(), doesNotApply) {
|
||||
logger.V(4).Info(fmt.Sprintf("skipping rule %s: %v", rule.Rule, err.Error()))
|
||||
}
|
||||
|
||||
policy, err := c.getPolicyObject(*ur)
|
||||
if err != nil {
|
||||
failures = append(failures, fmt.Errorf("rule %v failed: failed to get policy object: %s", rule.Rule, err))
|
||||
continue
|
||||
}
|
||||
|
||||
events := event.NewBackgroundFailedEvent(err, policy, ur.Spec.RuleContext[i].Rule, event.GeneratePolicyController,
|
||||
kyvernov1.ResourceSpec{Kind: trigger.GetKind(), Namespace: trigger.GetNamespace(), Name: trigger.GetName()})
|
||||
c.eventGen.Add(events...)
|
||||
}
|
||||
|
||||
events := event.NewBackgroundFailedEvent(err, policy, ur.Spec.Rule, event.GeneratePolicyController,
|
||||
kyvernov1.ResourceSpec{Kind: trigger.GetKind(), Namespace: trigger.GetNamespace(), Name: trigger.GetName()})
|
||||
c.eventGen.Add(events...)
|
||||
}
|
||||
|
||||
if err = updateStatus(c.statusControl, *ur, err, genResources); err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
return updateStatus(c.statusControl, *ur, multierr.Combine(failures...), genResources)
|
||||
}
|
||||
|
||||
const doesNotApply = "policy does not apply to resource"
|
||||
|
||||
func (c *GenerateController) getTrigger(spec kyvernov2.UpdateRequestSpec) (*unstructured.Unstructured, error) {
|
||||
func (c *GenerateController) getTrigger(spec kyvernov2.UpdateRequestSpec, i int) (*unstructured.Unstructured, error) {
|
||||
resourceSpec := spec.RuleContext[i].Trigger
|
||||
c.log.V(4).Info("fetching trigger", "trigger", resourceSpec.String())
|
||||
admissionRequest := spec.Context.AdmissionRequestInfo.AdmissionRequest
|
||||
if admissionRequest == nil {
|
||||
return common.GetResource(c.client, spec, c.log)
|
||||
return common.GetResource(c.client, resourceSpec, spec, c.log)
|
||||
} else {
|
||||
operation := spec.Context.AdmissionRequestInfo.Operation
|
||||
if operation == admissionv1.Delete {
|
||||
return c.getTriggerForDeleteOperation(spec)
|
||||
return c.getTriggerForDeleteOperation(spec, i)
|
||||
} else if operation == admissionv1.Create {
|
||||
return c.getTriggerForCreateOperation(spec)
|
||||
return c.getTriggerForCreateOperation(spec, i)
|
||||
} else {
|
||||
newResource, oldResource, err := admissionutils.ExtractResources(nil, *admissionRequest)
|
||||
if err != nil {
|
||||
|
@ -163,24 +158,26 @@ func (c *GenerateController) getTrigger(spec kyvernov2.UpdateRequestSpec) (*unst
|
|||
}
|
||||
}
|
||||
|
||||
func (c *GenerateController) getTriggerForDeleteOperation(spec kyvernov2.UpdateRequestSpec) (*unstructured.Unstructured, error) {
|
||||
func (c *GenerateController) getTriggerForDeleteOperation(spec kyvernov2.UpdateRequestSpec, i int) (*unstructured.Unstructured, error) {
|
||||
request := spec.Context.AdmissionRequestInfo.AdmissionRequest
|
||||
_, oldResource, err := admissionutils.ExtractResources(nil, *request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load resource from context: %w", err)
|
||||
}
|
||||
labels := oldResource.GetLabels()
|
||||
resourceSpec := spec.RuleContext[i].Trigger
|
||||
if labels[common.GeneratePolicyLabel] != "" {
|
||||
// non-trigger deletion, get trigger from ur spec
|
||||
c.log.V(4).Info("non-trigger resource is deleted, fetching the trigger from the UR spec", "trigger", spec.Resource.String())
|
||||
return common.GetResource(c.client, spec, c.log)
|
||||
return common.GetResource(c.client, resourceSpec, spec, c.log)
|
||||
}
|
||||
return &oldResource, nil
|
||||
}
|
||||
|
||||
func (c *GenerateController) getTriggerForCreateOperation(spec kyvernov2.UpdateRequestSpec) (*unstructured.Unstructured, error) {
|
||||
func (c *GenerateController) getTriggerForCreateOperation(spec kyvernov2.UpdateRequestSpec, i int) (*unstructured.Unstructured, error) {
|
||||
admissionRequest := spec.Context.AdmissionRequestInfo.AdmissionRequest
|
||||
trigger, err := common.GetResource(c.client, spec, c.log)
|
||||
resourceSpec := spec.RuleContext[i].Trigger
|
||||
trigger, err := common.GetResource(c.client, resourceSpec, spec, c.log)
|
||||
if err != nil || trigger == nil {
|
||||
if admissionRequest.SubResource == "" {
|
||||
return nil, err
|
||||
|
@ -197,22 +194,36 @@ func (c *GenerateController) getTriggerForCreateOperation(spec kyvernov2.UpdateR
|
|||
return trigger, err
|
||||
}
|
||||
|
||||
func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, ur kyvernov2.UpdateRequest, namespaceLabels map[string]string) ([]kyvernov1.ResourceSpec, error) {
|
||||
logger := c.log.WithValues("name", ur.GetName(), "policy", ur.Spec.GetPolicyKey(), "rule", ur.Spec.GetRuleName(), "resource", ur.Spec.GetResource().String())
|
||||
logger.V(3).Info("applying generate policy rule")
|
||||
func (c *GenerateController) applyGenerate(trigger unstructured.Unstructured, ur kyvernov2.UpdateRequest, i int, namespaceLabels map[string]string) ([]kyvernov1.ResourceSpec, error) {
|
||||
logger := c.log.WithValues("name", ur.GetName(), "policy", ur.Spec.GetPolicyKey())
|
||||
logger.V(3).Info("applying generate policy")
|
||||
|
||||
policy, err := c.getPolicySpec(ur)
|
||||
policy, err := c.getPolicyObject(ur)
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
logger.Error(err, "error in fetching policy")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ur.Spec.DeleteDownstream || apierrors.IsNotFound(err) {
|
||||
err = c.deleteDownstream(policy, &ur)
|
||||
ruleContext := ur.Spec.RuleContext[i]
|
||||
if ruleContext.DeleteDownstream || apierrors.IsNotFound(err) {
|
||||
err = c.deleteDownstream(policy, ruleContext, &ur)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
policyContext, err := common.NewBackgroundContext(logger, c.client, &ur, policy, &resource, c.configuration, c.jp, namespaceLabels)
|
||||
var rule *kyvernov1.Rule
|
||||
p := policy.CreateDeepCopy()
|
||||
for j := range p.GetSpec().Rules {
|
||||
if p.GetSpec().Rules[j].Name == ruleContext.Rule {
|
||||
rule = &p.GetSpec().Rules[j]
|
||||
break
|
||||
}
|
||||
}
|
||||
if rule == nil {
|
||||
logger.Info("skip rule application as the rule does not exist in the updaterequest", "rule", ruleContext.Rule)
|
||||
return nil, nil
|
||||
}
|
||||
p.GetSpec().SetRules([]kyvernov1.Rule{*rule})
|
||||
policyContext, err := common.NewBackgroundContext(logger, c.client, ur.Spec.Context, p, &trigger, c.configuration, c.jp, namespaceLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -235,62 +246,17 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, u
|
|||
}
|
||||
|
||||
var applicableRules []string
|
||||
// Removing UR if rule is failed. Used when the generate condition failed but ur exist
|
||||
for _, r := range engineResponse.PolicyResponse.Rules {
|
||||
if r.Name() != ur.Spec.GetRuleName() {
|
||||
continue
|
||||
}
|
||||
|
||||
if r.Status() != engineapi.RuleStatusPass {
|
||||
logger.V(4).Info("querying all update requests")
|
||||
selector := labels.SelectorFromSet(labels.Set(map[string]string{
|
||||
kyvernov2.URGeneratePolicyLabel: engineResponse.Policy().GetName(),
|
||||
kyvernov2.URGenerateResourceKindLabel: engineResponse.Resource.GetKind(),
|
||||
kyvernov2.URGenerateResourceNSLabel: engineResponse.Resource.GetNamespace(),
|
||||
}))
|
||||
// get update requests that have the resource UID label
|
||||
requirement, err := labels.NewRequirement(kyvernov2.URGenerateResourceUIDLabel, selection.Equals, []string{string(engineResponse.Resource.GetUID())})
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to add the resource UID label")
|
||||
}
|
||||
selectorWithResUID := selector.Add(*requirement)
|
||||
urList, err := c.urLister.List(selectorWithResUID)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to get update request for the resource", "kind", engineResponse.Resource.GetKind(), "name", engineResponse.Resource.GetName(), "namespace", engineResponse.Resource.GetNamespace())
|
||||
continue
|
||||
}
|
||||
|
||||
if len(urList) == 0 {
|
||||
// get update requests that have the resource name label
|
||||
requirement, err = labels.NewRequirement(kyvernov2.URGenerateResourceNameLabel, selection.Equals, []string{engineResponse.Resource.GetName()})
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to add the resource name label")
|
||||
continue
|
||||
}
|
||||
selectorWithResName := selector.Add(*requirement)
|
||||
urList, err = c.urLister.List(selectorWithResName)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to get update request for the resource", "kind", engineResponse.Resource.GetKind(), "name", engineResponse.Resource.GetName(), "namespace", engineResponse.Resource.GetNamespace())
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range urList {
|
||||
err := c.kyvernoClient.KyvernoV2().UpdateRequests(config.KyvernoNamespace()).Delete(context.TODO(), v.GetName(), metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to delete update request")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if r.Status() == engineapi.RuleStatusPass {
|
||||
applicableRules = append(applicableRules, r.Name())
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the generate rule on resource
|
||||
genResources, err := c.ApplyGeneratePolicy(logger, policyContext, ur, applicableRules)
|
||||
genResources, err := c.ApplyGeneratePolicy(logger, policyContext, applicableRules)
|
||||
if err == nil {
|
||||
for _, res := range genResources {
|
||||
e := event.NewResourceGenerationEvent(ur.Spec.Policy, ur.Spec.Rule, event.GeneratePolicyController, res)
|
||||
e := event.NewResourceGenerationEvent(ur.Spec.Policy, ur.Spec.RuleContext[i].Rule, event.GeneratePolicyController, res)
|
||||
c.eventGen.Add(e)
|
||||
}
|
||||
|
||||
|
@ -301,8 +267,8 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, u
|
|||
return genResources, err
|
||||
}
|
||||
|
||||
// getPolicySpec gets the policy spec from the ClusterPolicy/Policy
|
||||
func (c *GenerateController) getPolicySpec(ur kyvernov2.UpdateRequest) (kyvernov1.PolicyInterface, error) {
|
||||
// getPolicyObject gets the policy spec from the ClusterPolicy/Policy
|
||||
func (c *GenerateController) getPolicyObject(ur kyvernov2.UpdateRequest) (kyvernov1.PolicyInterface, error) {
|
||||
pNamespace, pName, err := cache.SplitMetaNamespaceKey(ur.Spec.Policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -335,12 +301,9 @@ func updateStatus(statusControl common.StatusControlInterface, ur kyvernov2.Upda
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext *engine.PolicyContext, ur kyvernov2.UpdateRequest, applicableRules []string) (genResources []kyvernov1.ResourceSpec, err error) {
|
||||
// Get the response as the actions to be performed on the resource
|
||||
// - - substitute values
|
||||
func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext *engine.PolicyContext, applicableRules []string) (genResources []kyvernov1.ResourceSpec, err error) {
|
||||
policy := policyContext.Policy()
|
||||
resource := policyContext.NewResource()
|
||||
jsonContext := policyContext.JSONContext()
|
||||
// To manage existing resources, we compare the creation time for the default resource to be generated and policy creation time
|
||||
ruleNameToProcessingTime := make(map[string]time.Duration)
|
||||
applyRules := policy.GetSpec().GetApplyRules()
|
||||
|
@ -355,7 +318,6 @@ func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext
|
|||
if !slices.Contains(applicableRules, rule.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if rule.Generation.Synchronize {
|
||||
ruleRaw, err := json.Marshal(rule.DeepCopy())
|
||||
if err != nil {
|
||||
|
@ -377,7 +339,7 @@ func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext
|
|||
if applyRules == kyvernov1.ApplyOne && applyCount > 0 {
|
||||
break
|
||||
}
|
||||
|
||||
logger := log.WithValues("rule", rule.Name)
|
||||
// add configmap json data to context
|
||||
if err := c.engine.ContextLoader(policyContext.Policy(), rule)(context.TODO(), rule.Context, policyContext.JSONContext()); err != nil {
|
||||
log.Error(err, "cannot add configmaps to context")
|
||||
|
@ -389,7 +351,7 @@ func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext
|
|||
return nil, err
|
||||
}
|
||||
|
||||
genResource, err = applyRule(log, c.client, rule, resource, jsonContext, policy, ur)
|
||||
genResource, err = applyRule(logger, c.client, rule, resource, policy)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to apply generate rule", "policy", policy.GetName(), "rule", rule.Name, "resource", resource.GetName())
|
||||
return nil, err
|
||||
|
@ -402,7 +364,7 @@ func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext
|
|||
return genResources, nil
|
||||
}
|
||||
|
||||
func applyRule(log logr.Logger, client dclient.Interface, rule kyvernov1.Rule, trigger unstructured.Unstructured, ctx enginecontext.EvalInterface, policy kyvernov1.PolicyInterface, ur kyvernov2.UpdateRequest) ([]kyvernov1.ResourceSpec, error) {
|
||||
func applyRule(log logr.Logger, client dclient.Interface, rule kyvernov1.Rule, trigger unstructured.Unstructured, policy kyvernov1.PolicyInterface) ([]kyvernov1.ResourceSpec, error) {
|
||||
responses := []generateResponse{}
|
||||
var err error
|
||||
var newGenResources []kyvernov1.ResourceSpec
|
||||
|
@ -411,12 +373,12 @@ func applyRule(log logr.Logger, client dclient.Interface, rule kyvernov1.Rule, t
|
|||
logger := log.WithValues("target", target.String())
|
||||
|
||||
if rule.Generation.Clone.Name != "" {
|
||||
resp := manageClone(logger.WithValues("type", "clone"), target, kyvernov1.ResourceSpec{}, policy, ur, rule, client)
|
||||
resp := manageClone(logger.WithValues("type", "clone"), target, kyvernov1.ResourceSpec{}, policy, rule, client)
|
||||
responses = append(responses, resp)
|
||||
} else if len(rule.Generation.CloneList.Kinds) != 0 {
|
||||
responses = manageCloneList(logger.WithValues("type", "cloneList"), target.GetNamespace(), ur, policy, rule, client)
|
||||
responses = manageCloneList(logger.WithValues("type", "cloneList"), target.GetNamespace(), policy, rule, client)
|
||||
} else {
|
||||
resp := manageData(logger.WithValues("type", "data"), target, rule.Generation.RawData, rule.Generation.Synchronize, ur, client)
|
||||
resp := manageData(logger.WithValues("type", "data"), target, rule.Generation.RawData, rule.Generation.Synchronize, client)
|
||||
responses = append(responses, resp)
|
||||
}
|
||||
|
||||
|
@ -464,7 +426,7 @@ func applyRule(log logr.Logger, client dclient.Interface, rule kyvernov1.Rule, t
|
|||
} else if response.GetAction() == Update {
|
||||
generatedObj, err := client.GetResource(context.TODO(), targetMeta.GetAPIVersion(), targetMeta.GetKind(), targetMeta.GetNamespace(), targetMeta.GetName())
|
||||
if err != nil {
|
||||
logger.V(2).Info("target resource not found, creating new target")
|
||||
logger.V(2).Info("creating new target due to the failure when fetching", "err", err.Error())
|
||||
if policy.GetSpec().UseServerSideApply {
|
||||
_, err = client.ApplyResource(context.TODO(), targetMeta.GetAPIVersion(), targetMeta.GetKind(), targetMeta.GetNamespace(), targetMeta.GetName(), newResource, false, "generate")
|
||||
} else {
|
||||
|
|
|
@ -43,7 +43,7 @@ func validateResourceElement(log logr.Logger, resourceElement, patternElement, o
|
|||
log.V(4).Info("Pattern and resource have different structures.", "path", path, "expected", fmt.Sprintf("%T", patternElement), "current", fmt.Sprintf("%T", resourceElement))
|
||||
return path, fmt.Errorf("pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
|
||||
}
|
||||
return validateMap(log, typedResourceElement, typedPatternElement, originPattern, path)
|
||||
return validateMap(typedResourceElement, typedPatternElement, originPattern, path)
|
||||
// array
|
||||
case []interface{}:
|
||||
typedResourceElement, ok := resourceElement.([]interface{})
|
||||
|
@ -67,7 +67,7 @@ func validateResourceElement(log logr.Logger, resourceElement, patternElement, o
|
|||
|
||||
// If validateResourceElement detects map element inside resource and pattern trees, it goes to validateMap
|
||||
// For each element of the map we must detect the type again, so we pass these elements to validateResourceElement
|
||||
func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string) (string, error) {
|
||||
func validateMap(resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string) (string, error) {
|
||||
patternMap = wildcards.ExpandInMetadata(patternMap, resourceMap)
|
||||
sortedResourceKeys := list.New()
|
||||
for k := range patternMap {
|
||||
|
|
|
@ -94,7 +94,7 @@ func (c *mutateExistingController) ProcessUR(ur *kyvernov2.UpdateRequest) error
|
|||
var trigger *unstructured.Unstructured
|
||||
admissionRequest := ur.Spec.Context.AdmissionRequestInfo.AdmissionRequest
|
||||
if admissionRequest == nil {
|
||||
trigger, err = common.GetResource(c.client, ur.Spec, c.log)
|
||||
trigger, err = common.GetResource(c.client, ur.Spec.Resource, ur.Spec, c.log)
|
||||
if err != nil || trigger == nil {
|
||||
logger.WithName(rule.Name).Error(err, "failed to get trigger resource")
|
||||
if err := updateURStatus(c.statusControl, *ur, err); err != nil {
|
||||
|
@ -104,7 +104,7 @@ func (c *mutateExistingController) ProcessUR(ur *kyvernov2.UpdateRequest) error
|
|||
}
|
||||
} else {
|
||||
if admissionRequest.Operation == admissionv1.Create {
|
||||
trigger, err = common.GetResource(c.client, ur.Spec, c.log)
|
||||
trigger, err = common.GetResource(c.client, ur.Spec.Resource, ur.Spec, c.log)
|
||||
if err != nil || trigger == nil {
|
||||
if admissionRequest.SubResource == "" {
|
||||
logger.WithName(rule.Name).Error(err, "failed to get trigger resource")
|
||||
|
@ -139,7 +139,7 @@ func (c *mutateExistingController) ProcessUR(ur *kyvernov2.UpdateRequest) error
|
|||
}
|
||||
|
||||
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(trigger.GetKind(), trigger.GetNamespace(), c.nsLister, logger)
|
||||
policyContext, err := common.NewBackgroundContext(logger, c.client, ur, policy, trigger, c.configuration, c.jp, namespaceLabels)
|
||||
policyContext, err := common.NewBackgroundContext(logger, c.client, ur.Spec.Context, policy, trigger, c.configuration, c.jp, namespaceLabels)
|
||||
if err != nil {
|
||||
logger.WithName(rule.Name).Error(err, "failed to build policy context")
|
||||
errs = append(errs, err)
|
||||
|
|
70
pkg/client/applyconfigurations/kyverno/v2/rulecontext.go
Normal file
70
pkg/client/applyconfigurations/kyverno/v2/rulecontext.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||
|
||||
package v2
|
||||
|
||||
import (
|
||||
v1 "github.com/kyverno/kyverno/pkg/client/applyconfigurations/kyverno/v1"
|
||||
)
|
||||
|
||||
// RuleContextApplyConfiguration represents an declarative configuration of the RuleContext type for use
|
||||
// with apply.
|
||||
type RuleContextApplyConfiguration struct {
|
||||
Rule *string `json:"rule,omitempty"`
|
||||
DeleteDownstream *bool `json:"deleteDownstream,omitempty"`
|
||||
Synchronize *bool `json:"synchronize,omitempty"`
|
||||
Trigger *v1.ResourceSpecApplyConfiguration `json:"trigger,omitempty"`
|
||||
}
|
||||
|
||||
// RuleContextApplyConfiguration constructs an declarative configuration of the RuleContext type for use with
|
||||
// apply.
|
||||
func RuleContext() *RuleContextApplyConfiguration {
|
||||
return &RuleContextApplyConfiguration{}
|
||||
}
|
||||
|
||||
// WithRule sets the Rule field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Rule field is set to the value of the last call.
|
||||
func (b *RuleContextApplyConfiguration) WithRule(value string) *RuleContextApplyConfiguration {
|
||||
b.Rule = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithDeleteDownstream sets the DeleteDownstream field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the DeleteDownstream field is set to the value of the last call.
|
||||
func (b *RuleContextApplyConfiguration) WithDeleteDownstream(value bool) *RuleContextApplyConfiguration {
|
||||
b.DeleteDownstream = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithSynchronize sets the Synchronize field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Synchronize field is set to the value of the last call.
|
||||
func (b *RuleContextApplyConfiguration) WithSynchronize(value bool) *RuleContextApplyConfiguration {
|
||||
b.Synchronize = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithTrigger sets the Trigger field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Trigger field is set to the value of the last call.
|
||||
func (b *RuleContextApplyConfiguration) WithTrigger(value *v1.ResourceSpecApplyConfiguration) *RuleContextApplyConfiguration {
|
||||
b.Trigger = value
|
||||
return b
|
||||
}
|
|
@ -28,6 +28,7 @@ import (
|
|||
type UpdateRequestSpecApplyConfiguration struct {
|
||||
Type *v2.RequestType `json:"requestType,omitempty"`
|
||||
Policy *string `json:"policy,omitempty"`
|
||||
RuleContext []RuleContextApplyConfiguration `json:"ruleContext,omitempty"`
|
||||
Rule *string `json:"rule,omitempty"`
|
||||
DeleteDownstream *bool `json:"deleteDownstream,omitempty"`
|
||||
Synchronize *bool `json:"synchronize,omitempty"`
|
||||
|
@ -57,6 +58,19 @@ func (b *UpdateRequestSpecApplyConfiguration) WithPolicy(value string) *UpdateRe
|
|||
return b
|
||||
}
|
||||
|
||||
// WithRuleContext adds the given value to the RuleContext field in the declarative configuration
|
||||
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||
// If called multiple times, values provided by each call will be appended to the RuleContext field.
|
||||
func (b *UpdateRequestSpecApplyConfiguration) WithRuleContext(values ...*RuleContextApplyConfiguration) *UpdateRequestSpecApplyConfiguration {
|
||||
for i := range values {
|
||||
if values[i] == nil {
|
||||
panic("nil value passed to WithRuleContext")
|
||||
}
|
||||
b.RuleContext = append(b.RuleContext, *values[i])
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// WithRule sets the Rule field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Rule field is set to the value of the last call.
|
||||
|
|
|
@ -185,6 +185,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
|||
return &kyvernov2.PolicyExceptionSpecApplyConfiguration{}
|
||||
case v2.SchemeGroupVersion.WithKind("RequestInfo"):
|
||||
return &kyvernov2.RequestInfoApplyConfiguration{}
|
||||
case v2.SchemeGroupVersion.WithKind("RuleContext"):
|
||||
return &kyvernov2.RuleContextApplyConfiguration{}
|
||||
case v2.SchemeGroupVersion.WithKind("UpdateRequest"):
|
||||
return &kyvernov2.UpdateRequestApplyConfiguration{}
|
||||
case v2.SchemeGroupVersion.WithKind("UpdateRequestSpec"):
|
||||
|
|
|
@ -167,6 +167,12 @@ func NewBackgroundFailedEvent(err error, policy kyvernov1.PolicyInterface, rule
|
|||
Namespace: policy.GetNamespace(),
|
||||
UID: policy.GetUID(),
|
||||
}
|
||||
var msg string
|
||||
if rule == "" {
|
||||
msg = fmt.Sprintf("policy %s error: %v", policy.GetName(), err)
|
||||
} else {
|
||||
msg = fmt.Sprintf("policy %s/%s error: %v", policy.GetName(), rule, err)
|
||||
}
|
||||
events = append(events, Info{
|
||||
Regarding: regarding,
|
||||
Related: &corev1.ObjectReference{
|
||||
|
@ -178,7 +184,7 @@ func NewBackgroundFailedEvent(err error, policy kyvernov1.PolicyInterface, rule
|
|||
},
|
||||
Source: source,
|
||||
Reason: PolicyError,
|
||||
Message: fmt.Sprintf("policy %s/%s error: %v", policy.GetName(), rule, err),
|
||||
Message: msg,
|
||||
Action: None,
|
||||
})
|
||||
|
||||
|
@ -366,6 +372,12 @@ func NewValidatingAdmissionPolicyEvent(policy kyvernov1.PolicyInterface, vapName
|
|||
}
|
||||
|
||||
func NewFailedEvent(err error, policy, rule string, source Source, resource kyvernov1.ResourceSpec) Info {
|
||||
var msg string
|
||||
if rule == "" {
|
||||
msg = fmt.Sprintf("policy %s error: %v", policy, err)
|
||||
} else {
|
||||
msg = fmt.Sprintf("policy %s/%s error: %v", policy, rule, err)
|
||||
}
|
||||
return Info{
|
||||
Regarding: corev1.ObjectReference{
|
||||
APIVersion: resource.APIVersion,
|
||||
|
@ -376,7 +388,7 @@ func NewFailedEvent(err error, policy, rule string, source Source, resource kyve
|
|||
},
|
||||
Source: source,
|
||||
Reason: PolicyError,
|
||||
Message: fmt.Sprintf("policy %s/%s error: %v", policy, rule, err),
|
||||
Message: msg,
|
||||
Action: None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/background/common"
|
||||
generateutils "github.com/kyverno/kyverno/pkg/background/generate"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/utils/engine"
|
||||
"go.uber.org/multierr"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
@ -25,10 +26,6 @@ func (pc *policyController) handleGenerate(policyKey string, policy kyvernov1.Po
|
|||
return err
|
||||
}
|
||||
|
||||
if !policy.GetSpec().IsGenerateExisting() {
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.V(4).Info("reconcile policy with generateExisting enabled")
|
||||
if err := pc.handleGenerateForExisting(policy); err != nil {
|
||||
logger.Error(err, "failed to create UR for generateExisting")
|
||||
|
@ -37,65 +34,9 @@ func (pc *policyController) handleGenerate(policyKey string, policy kyvernov1.Po
|
|||
return nil
|
||||
}
|
||||
|
||||
func (pc *policyController) handleGenerateForExisting(policy kyvernov1.PolicyInterface) error {
|
||||
var errors []error
|
||||
var triggers []*unstructured.Unstructured
|
||||
ruleType := kyvernov2.Generate
|
||||
spec := policy.GetSpec()
|
||||
policyNew := policy.CreateDeepCopy()
|
||||
policyNew.GetSpec().Rules = nil
|
||||
|
||||
for _, rule := range spec.Rules {
|
||||
// check if the rule sets the generateExisting field.
|
||||
// if not, use the policy level setting
|
||||
generateExisting := rule.Generation.GenerateExisting
|
||||
if generateExisting != nil {
|
||||
if !*generateExisting {
|
||||
continue
|
||||
}
|
||||
} else if !spec.GenerateExisting {
|
||||
continue
|
||||
}
|
||||
|
||||
triggers = getTriggers(pc.client, rule, policy.IsNamespaced(), policy.GetNamespace(), pc.log)
|
||||
policyNew.GetSpec().SetRules([]kyvernov1.Rule{rule})
|
||||
for _, trigger := range triggers {
|
||||
ur := newUR(policyNew, common.ResourceSpecFromUnstructured(*trigger), rule.Name, ruleType, false)
|
||||
skip, err := pc.handleUpdateRequest(ur, trigger, rule.Name, policyNew)
|
||||
if err != nil {
|
||||
pc.log.Error(err, "failed to create new UR on policy update", "policy", policyNew.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
|
||||
errors = append(errors, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
|
||||
pc.log.V(4).Info("successfully created UR on policy update", "policy", policyNew.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errors...)
|
||||
}
|
||||
|
||||
func (pc *policyController) createURForDownstreamDeletion(policy kyvernov1.PolicyInterface) error {
|
||||
var errs []error
|
||||
rules := autogen.ComputeRules(policy, "")
|
||||
for _, r := range rules {
|
||||
generateType, sync, orphanDownstreamOnPolicyDelete := r.GetTypeAndSyncAndOrphanDownstream()
|
||||
if sync && (generateType == kyvernov1.Data) && !orphanDownstreamOnPolicyDelete {
|
||||
if err := pc.syncDataPolicyChanges(policy, true); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
|
||||
func (pc *policyController) syncDataPolicyChanges(policy kyvernov1.PolicyInterface, deleteDownstream bool) error {
|
||||
var errorList []error
|
||||
var errs []error
|
||||
ur := newGenerateUR(policy)
|
||||
for _, rule := range policy.GetSpec().Rules {
|
||||
generate := rule.Generation
|
||||
if !generate.Synchronize {
|
||||
|
@ -104,14 +45,139 @@ func (pc *policyController) syncDataPolicyChanges(policy kyvernov1.PolicyInterfa
|
|||
if generate.GetData() == nil {
|
||||
continue
|
||||
}
|
||||
if err := pc.syncDataRulechanges(policy, rule, deleteDownstream); err != nil {
|
||||
errorList = append(errorList, err)
|
||||
var err error
|
||||
if ur, err = pc.buildUrForDataRuleChanges(policy, ur, rule, deleteDownstream, false); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errorList...)
|
||||
|
||||
if len(ur.Spec.RuleContext) == 0 {
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
pc.log.V(2).WithName("syncDataPolicyChanges").Info("creating new UR for generate")
|
||||
created, err := pc.urGenerator.Generate(context.TODO(), pc.kyvernoClient, ur, pc.log)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if created != nil {
|
||||
updated := created.DeepCopy()
|
||||
updated.Status.State = kyvernov2.Pending
|
||||
_, err = pc.kyvernoClient.KyvernoV2().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), updated, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
|
||||
func (pc *policyController) syncDataRulechanges(policy kyvernov1.PolicyInterface, rule kyvernov1.Rule, deleteDownstream bool) error {
|
||||
func (pc *policyController) handleGenerateForExisting(policy kyvernov1.PolicyInterface) error {
|
||||
var errors []error
|
||||
var triggers []*unstructured.Unstructured
|
||||
policyNew := policy.CreateDeepCopy()
|
||||
policyNew.GetSpec().Rules = nil
|
||||
ur := newGenerateUR(policy)
|
||||
logger := pc.log.WithName("handleGenerateForExisting")
|
||||
for _, rule := range policy.GetSpec().Rules {
|
||||
if !rule.HasGenerate() {
|
||||
continue
|
||||
}
|
||||
|
||||
// check if the rule sets the generateExisting field.
|
||||
// if not, use the policy level setting
|
||||
generateExisting := rule.Generation.GenerateExisting
|
||||
if generateExisting != nil {
|
||||
if !*generateExisting {
|
||||
continue
|
||||
}
|
||||
} else if !policy.GetSpec().GenerateExisting {
|
||||
continue
|
||||
}
|
||||
|
||||
triggers = getTriggers(pc.client, rule, policy.IsNamespaced(), policy.GetNamespace(), pc.log)
|
||||
policyNew.GetSpec().SetRules([]kyvernov1.Rule{rule})
|
||||
for _, trigger := range triggers {
|
||||
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(trigger.GetKind(), trigger.GetNamespace(), pc.nsLister, pc.log)
|
||||
policyContext, err := common.NewBackgroundContext(pc.log, pc.client, ur.Spec.Context, policy, trigger, pc.configuration, pc.jp, namespaceLabels)
|
||||
if err != nil {
|
||||
errors = append(errors, fmt.Errorf("failed to build policy context for rule %s: %w", rule.Name, err))
|
||||
continue
|
||||
}
|
||||
|
||||
engineResponse := pc.engine.ApplyBackgroundChecks(context.TODO(), policyContext)
|
||||
if len(engineResponse.PolicyResponse.Rules) == 0 {
|
||||
continue
|
||||
}
|
||||
logger.V(4).Info("adding rule context", "rule", rule.Name, "trigger", trigger.GetNamespace()+"/"+trigger.GetName())
|
||||
addRuleContext(ur, rule.Name, common.ResourceSpecFromUnstructured(*trigger), false)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ur.Spec.RuleContext) == 0 {
|
||||
return multierr.Combine(errors...)
|
||||
}
|
||||
|
||||
logger.V(2).Info("creating new UR for generate")
|
||||
created, err := pc.urGenerator.Generate(context.TODO(), pc.kyvernoClient, ur, pc.log)
|
||||
if err != nil {
|
||||
errors = append(errors, err)
|
||||
return multierr.Combine(errors...)
|
||||
}
|
||||
if created != nil {
|
||||
updated := created.DeepCopy()
|
||||
updated.Status.State = kyvernov2.Pending
|
||||
_, err = pc.kyvernoClient.KyvernoV2().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), updated, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
errors = append(errors, err)
|
||||
return multierr.Combine(errors...)
|
||||
}
|
||||
pc.log.V(4).Info("successfully created UR on policy update", "policy", policyNew.GetName())
|
||||
}
|
||||
return multierr.Combine(errors...)
|
||||
}
|
||||
|
||||
func (pc *policyController) createURForDownstreamDeletion(policy kyvernov1.PolicyInterface) error {
|
||||
var errs []error
|
||||
rules := autogen.ComputeRules(policy, "")
|
||||
ur := newGenerateUR(policy)
|
||||
for _, r := range rules {
|
||||
generate := r.Generation
|
||||
if !generate.Synchronize {
|
||||
continue
|
||||
}
|
||||
if generate.GetData() == nil {
|
||||
continue
|
||||
}
|
||||
generateType, sync, orphanDownstreamOnPolicyDelete := r.GetTypeAndSyncAndOrphanDownstream()
|
||||
if sync && (generateType == kyvernov1.Data) && !orphanDownstreamOnPolicyDelete {
|
||||
var err error
|
||||
if ur, err = pc.buildUrForDataRuleChanges(policy, ur, r, true, true); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(ur.Spec.RuleContext) == 0 {
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
|
||||
pc.log.V(2).WithName("createURForDownstreamDeletion").Info("creating new UR for generate")
|
||||
created, err := pc.urGenerator.Generate(context.TODO(), pc.kyvernoClient, ur, pc.log)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if created != nil {
|
||||
updated := created.DeepCopy()
|
||||
updated.Status.State = kyvernov2.Pending
|
||||
updated.Status.GeneratedResources = ur.Status.GeneratedResources
|
||||
_, err = pc.kyvernoClient.KyvernoV2().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), updated, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
|
||||
func (pc *policyController) buildUrForDataRuleChanges(policy kyvernov1.PolicyInterface, ur *kyvernov2.UpdateRequest, rule kyvernov1.Rule, deleteDownstream, policyDeletion bool) (*kyvernov2.UpdateRequest, error) {
|
||||
labels := map[string]string{
|
||||
common.GeneratePolicyLabel: policy.GetName(),
|
||||
common.GeneratePolicyNamespaceLabel: policy.GetNamespace(),
|
||||
|
@ -121,29 +187,24 @@ func (pc *policyController) syncDataRulechanges(policy kyvernov1.PolicyInterface
|
|||
|
||||
downstreams, err := common.FindDownstream(pc.client, rule.Generation.GetAPIVersion(), rule.Generation.GetKind(), labels)
|
||||
if err != nil {
|
||||
return err
|
||||
return ur, err
|
||||
}
|
||||
|
||||
if len(downstreams.Items) == 0 {
|
||||
return ur, nil
|
||||
}
|
||||
|
||||
pc.log.V(4).Info("sync data rule changes to downstream targets")
|
||||
var errorList []error
|
||||
for _, downstream := range downstreams.Items {
|
||||
labels := downstream.GetLabels()
|
||||
trigger := generateutils.TriggerFromLabels(labels)
|
||||
ur := newUR(policy, trigger, rule.Name, kyvernov2.Generate, deleteDownstream)
|
||||
created, err := pc.kyvernoClient.KyvernoV2().UpdateRequests(config.KyvernoNamespace()).Create(context.TODO(), ur, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
errorList = append(errorList, err)
|
||||
continue
|
||||
}
|
||||
updated := created.DeepCopy()
|
||||
updated.Status = newURStatus(downstream)
|
||||
_, err = pc.kyvernoClient.KyvernoV2().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), updated, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
errorList = append(errorList, err)
|
||||
continue
|
||||
addRuleContext(ur, rule.Name, trigger, deleteDownstream)
|
||||
if policyDeletion {
|
||||
addGeneratedResources(ur, downstream)
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errorList...)
|
||||
|
||||
return ur, nil
|
||||
}
|
||||
|
||||
// ruleDeletion returns true if any rule is deleted, along with deleted rules
|
||||
|
|
|
@ -43,7 +43,7 @@ func (pc *policyController) handleMutate(policyKey string, policy kyvernov1.Poli
|
|||
}
|
||||
|
||||
logger.Info("creating new UR for mutate")
|
||||
ur := newUR(policy, backgroundcommon.ResourceSpecFromUnstructured(*trigger), rule.Name, ruleType, false)
|
||||
ur := newMutateUR(policy, backgroundcommon.ResourceSpecFromUnstructured(*trigger), rule.Name)
|
||||
skip, err := pc.handleUpdateRequest(ur, trigger, rule.Name, policyNew)
|
||||
if err != nil {
|
||||
pc.log.Error(err, "failed to create new UR on policy update", "policy", policyNew.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
|
|
|
@ -398,7 +398,7 @@ func (pc *policyController) requeuePolicies() {
|
|||
|
||||
func (pc *policyController) handleUpdateRequest(ur *kyvernov2.UpdateRequest, triggerResource *unstructured.Unstructured, ruleName string, policy kyvernov1.PolicyInterface) (skip bool, err error) {
|
||||
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(triggerResource.GetKind(), triggerResource.GetNamespace(), pc.nsLister, pc.log)
|
||||
policyContext, err := backgroundcommon.NewBackgroundContext(pc.log, pc.client, ur, policy, triggerResource, pc.configuration, pc.jp, namespaceLabels)
|
||||
policyContext, err := backgroundcommon.NewBackgroundContext(pc.log, pc.client, ur.Spec.Context, policy, triggerResource, pc.configuration, pc.jp, namespaceLabels)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to build policy context for rule %s: %w", ruleName, err)
|
||||
}
|
||||
|
|
|
@ -7,25 +7,37 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/config"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
func newUR(policy kyvernov1.PolicyInterface, trigger kyvernov1.ResourceSpec, ruleName string, ruleType kyvernov2.RequestType, deleteDownstream bool) *kyvernov2.UpdateRequest {
|
||||
var policyNameNamespaceKey string
|
||||
|
||||
if policy.IsNamespaced() {
|
||||
policyNameNamespaceKey = policy.GetNamespace() + "/" + policy.GetName()
|
||||
} else {
|
||||
policyNameNamespaceKey = policy.GetName()
|
||||
func newMutateUR(policy kyvernov1.PolicyInterface, trigger kyvernov1.ResourceSpec, ruleName string) *kyvernov2.UpdateRequest {
|
||||
ur := newUrMeta()
|
||||
ur.Labels = common.MutateLabelsSet(policyKey(policy), trigger)
|
||||
ur.Spec = kyvernov2.UpdateRequestSpec{
|
||||
Type: kyvernov2.Mutate,
|
||||
Policy: policyKey(policy),
|
||||
Rule: ruleName,
|
||||
Resource: kyvernov1.ResourceSpec{
|
||||
Kind: trigger.GetKind(),
|
||||
Namespace: trigger.GetNamespace(),
|
||||
Name: trigger.GetName(),
|
||||
APIVersion: trigger.GetAPIVersion(),
|
||||
UID: trigger.GetUID(),
|
||||
},
|
||||
}
|
||||
return ur
|
||||
}
|
||||
|
||||
var label labels.Set
|
||||
if ruleType == kyvernov2.Mutate {
|
||||
label = common.MutateLabelsSet(policyNameNamespaceKey, trigger)
|
||||
} else {
|
||||
label = common.GenerateLabelsSet(policyNameNamespaceKey, trigger)
|
||||
func newGenerateUR(policy kyvernov1.PolicyInterface) *kyvernov2.UpdateRequest {
|
||||
ur := newUrMeta()
|
||||
ur.Labels = common.GenerateLabelsSet(policyKey(policy))
|
||||
ur.Spec = kyvernov2.UpdateRequestSpec{
|
||||
Type: kyvernov2.Generate,
|
||||
Policy: policyKey(policy),
|
||||
}
|
||||
return ur
|
||||
}
|
||||
|
||||
func newUrMeta() *kyvernov2.UpdateRequest {
|
||||
return &kyvernov2.UpdateRequest{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: kyvernov2.SchemeGroupVersion.String(),
|
||||
|
@ -34,35 +46,32 @@ func newUR(policy kyvernov1.PolicyInterface, trigger kyvernov1.ResourceSpec, rul
|
|||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: "ur-",
|
||||
Namespace: config.KyvernoNamespace(),
|
||||
Labels: label,
|
||||
},
|
||||
Spec: kyvernov2.UpdateRequestSpec{
|
||||
Type: ruleType,
|
||||
Policy: policyNameNamespaceKey,
|
||||
Rule: ruleName,
|
||||
Resource: kyvernov1.ResourceSpec{
|
||||
Kind: trigger.GetKind(),
|
||||
Namespace: trigger.GetNamespace(),
|
||||
Name: trigger.GetName(),
|
||||
APIVersion: trigger.GetAPIVersion(),
|
||||
UID: trigger.GetUID(),
|
||||
},
|
||||
DeleteDownstream: deleteDownstream,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newURStatus(downstream unstructured.Unstructured) kyvernov2.UpdateRequestStatus {
|
||||
return kyvernov2.UpdateRequestStatus{
|
||||
State: kyvernov2.Pending,
|
||||
GeneratedResources: []kyvernov1.ResourceSpec{
|
||||
{
|
||||
APIVersion: downstream.GetAPIVersion(),
|
||||
Kind: downstream.GetKind(),
|
||||
Namespace: downstream.GetNamespace(),
|
||||
Name: downstream.GetName(),
|
||||
UID: downstream.GetUID(),
|
||||
},
|
||||
func addGeneratedResources(ur *kyvernov2.UpdateRequest, downstream unstructured.Unstructured) {
|
||||
ur.Status.GeneratedResources = append(ur.Status.GeneratedResources,
|
||||
kyvernov1.ResourceSpec{
|
||||
APIVersion: downstream.GetAPIVersion(),
|
||||
Kind: downstream.GetKind(),
|
||||
Namespace: downstream.GetNamespace(),
|
||||
Name: downstream.GetName(),
|
||||
UID: downstream.GetUID(),
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func addRuleContext(ur *kyvernov2.UpdateRequest, ruleName string, trigger kyvernov1.ResourceSpec, deleteDownstream bool) {
|
||||
ur.Spec.RuleContext = append(ur.Spec.RuleContext, kyvernov2.RuleContext{
|
||||
Rule: ruleName,
|
||||
Trigger: kyvernov1.ResourceSpec{
|
||||
Kind: trigger.GetKind(),
|
||||
Namespace: trigger.GetNamespace(),
|
||||
Name: trigger.GetName(),
|
||||
APIVersion: trigger.GetAPIVersion(),
|
||||
UID: trigger.GetUID(),
|
||||
},
|
||||
DeleteDownstream: deleteDownstream,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -37,3 +37,14 @@ func castPolicy(p interface{}) kyvernov1.PolicyInterface {
|
|||
}
|
||||
return policy
|
||||
}
|
||||
|
||||
func policyKey(policy kyvernov1.PolicyInterface) string {
|
||||
var policyNameNamespaceKey string
|
||||
|
||||
if policy.IsNamespaced() {
|
||||
policyNameNamespaceKey = policy.GetNamespace() + "/" + policy.GetName()
|
||||
} else {
|
||||
policyNameNamespaceKey = policy.GetName()
|
||||
}
|
||||
return policyNameNamespaceKey
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ func (h *generationHandler) Handle(
|
|||
if h.backgroundServiceAccountName == policyContext.AdmissionInfo().AdmissionUserInfo.Username {
|
||||
return
|
||||
}
|
||||
h.handleNonTrigger(ctx, policyContext, request)
|
||||
h.handleNonTrigger(ctx, policyContext)
|
||||
}
|
||||
|
||||
func getAppliedRules(policy kyvernov1.PolicyInterface, applied []engineapi.RuleResponse) []kyvernov1.Rule {
|
||||
|
@ -137,13 +137,12 @@ func (h *generationHandler) handleTrigger(
|
|||
func (h *generationHandler) handleNonTrigger(
|
||||
ctx context.Context,
|
||||
policyContext *engine.PolicyContext,
|
||||
request admissionv1.AdmissionRequest,
|
||||
) {
|
||||
resource := policyContext.OldResource()
|
||||
labels := resource.GetLabels()
|
||||
if _, ok := labels[common.GenerateTypeCloneSourceLabel]; ok || labels[common.GeneratePolicyLabel] != "" {
|
||||
h.log.V(4).Info("handle non-trigger resource operation for generate")
|
||||
if err := h.processRequest(ctx, policyContext, request); err != nil {
|
||||
if err := h.processRequest(ctx, policyContext); err != nil {
|
||||
h.log.Error(err, "failed to create the UR on non-trigger admission request")
|
||||
}
|
||||
}
|
||||
|
@ -171,16 +170,14 @@ func (h *generationHandler) applyGeneration(
|
|||
}
|
||||
|
||||
rules := getAppliedRules(policy, appliedRules)
|
||||
for _, rule := range rules {
|
||||
h.log.V(4).Info("creating the UR to generate downstream on trigger's operation", "operation", request.Operation, "rule", rule.Name)
|
||||
urSpec := buildURSpec(kyvernov2.Generate, pKey, rule.Name, triggerSpec, false)
|
||||
urSpec.Context = buildURContext(request, policyContext)
|
||||
if err := h.urGenerator.Apply(ctx, urSpec); err != nil {
|
||||
h.log.Error(err, "failed to create the UR to create downstream on trigger's operation", "operation", request.Operation, "rule", rule.Name)
|
||||
e := event.NewFailedEvent(err, pKey, rule.Name, event.GeneratePolicyController,
|
||||
kyvernov1.ResourceSpec{Kind: policy.GetKind(), Namespace: policy.GetNamespace(), Name: policy.GetName()})
|
||||
h.eventGen.Add(e)
|
||||
}
|
||||
h.log.V(4).Info("creating the UR to generate downstream on trigger's operation", "operation", request.Operation, "policy", pKey)
|
||||
urSpec := buildURSpecNew(kyvernov2.Generate, pKey, rules, triggerSpec, false)
|
||||
urSpec.Context = buildURContext(request, policyContext)
|
||||
if err := h.urGenerator.Apply(ctx, urSpec); err != nil {
|
||||
h.log.Error(err, "failed to create the UR to create downstream on trigger's operation", "operation", request.Operation, "policy", pKey)
|
||||
e := event.NewFailedEvent(err, pKey, "", event.GeneratePolicyController,
|
||||
kyvernov1.ResourceSpec{Kind: policy.GetKind(), Namespace: policy.GetNamespace(), Name: policy.GetName()})
|
||||
h.eventGen.Add(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,7 +196,7 @@ func (h *generationHandler) syncTriggerAction(
|
|||
|
||||
pKey := common.PolicyKey(policy.GetNamespace(), policy.GetName())
|
||||
trigger := policyContext.OldResource()
|
||||
urSpec := kyvernov1.ResourceSpec{
|
||||
triggerSpec := kyvernov1.ResourceSpec{
|
||||
APIVersion: trigger.GetAPIVersion(),
|
||||
Kind: trigger.GetKind(),
|
||||
Namespace: trigger.GetNamespace(),
|
||||
|
@ -208,38 +205,39 @@ func (h *generationHandler) syncTriggerAction(
|
|||
}
|
||||
|
||||
rules := getAppliedRules(policy, failedRules)
|
||||
urSpec := kyvernov2.UpdateRequestSpec{
|
||||
Type: kyvernov2.Generate,
|
||||
Policy: pKey,
|
||||
RuleContext: make([]kyvernov2.RuleContext, 0),
|
||||
Context: buildURContext(request, policyContext),
|
||||
}
|
||||
for _, rule := range rules {
|
||||
// fire generation on trigger deletion
|
||||
if (request.Operation == admissionv1.Delete) && webhookutils.MatchDeleteOperation(rule) {
|
||||
h.log.V(4).Info("creating the UR to generate downstream on trigger's deletion", "operation", request.Operation, "rule", rule.Name)
|
||||
ur := buildURSpec(kyvernov2.Generate, pKey, rule.Name, urSpec, false)
|
||||
ur.Context = buildURContext(request, policyContext)
|
||||
if err := h.urGenerator.Apply(ctx, ur); err != nil {
|
||||
h.log.Error(err, "failed to create the UR to generate downstream on trigger's deletion", "operation", request.Operation, "rule", rule.Name)
|
||||
e := event.NewFailedEvent(err, pKey, rule.Name, event.GeneratePolicyController,
|
||||
kyvernov1.ResourceSpec{Kind: policy.GetKind(), Namespace: policy.GetNamespace(), Name: policy.GetName()})
|
||||
h.eventGen.Add(e)
|
||||
}
|
||||
ruleCtx := buildRuleContext(rule, triggerSpec, false)
|
||||
urSpec.RuleContext = append(urSpec.RuleContext, ruleCtx)
|
||||
continue
|
||||
}
|
||||
|
||||
// delete downstream on trigger deletion
|
||||
if rule.Generation.Synchronize {
|
||||
h.log.V(4).Info("creating the UR to delete downstream on trigger's event", "operation", request.Operation, "rule", rule.Name)
|
||||
ur := buildURSpec(kyvernov2.Generate, pKey, rule.Name, urSpec, true)
|
||||
ur.Context = buildURContext(request, policyContext)
|
||||
if err := h.urGenerator.Apply(ctx, ur); err != nil {
|
||||
h.log.Error(err, "failed to create the UR to delete downstream on trigger's event", "operation", request.Operation, "rule", rule.Name)
|
||||
e := event.NewFailedEvent(err, pKey, rule.Name, event.GeneratePolicyController,
|
||||
kyvernov1.ResourceSpec{Kind: policy.GetKind(), Namespace: policy.GetNamespace(), Name: policy.GetName()})
|
||||
h.eventGen.Add(e)
|
||||
}
|
||||
ruleCtx := buildRuleContext(rule, triggerSpec, true)
|
||||
urSpec.RuleContext = append(urSpec.RuleContext, ruleCtx)
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.urGenerator.Apply(ctx, urSpec); err != nil {
|
||||
h.log.Error(err, "failed to create the UR on trigger's event", "operation", request.Operation, "policy", pKey)
|
||||
e := event.NewFailedEvent(err, pKey, "", event.GeneratePolicyController,
|
||||
kyvernov1.ResourceSpec{Kind: policy.GetKind(), Namespace: policy.GetNamespace(), Name: policy.GetName()})
|
||||
h.eventGen.Add(e)
|
||||
}
|
||||
}
|
||||
|
||||
// processRequest determine if it needs to re-apply the generate rule to the source or the target changes
|
||||
func (h *generationHandler) processRequest(ctx context.Context, policyContext *engine.PolicyContext, request admissionv1.AdmissionRequest) (err error) {
|
||||
func (h *generationHandler) processRequest(ctx context.Context, policyContext *engine.PolicyContext) (err error) {
|
||||
var policy kyvernov1.PolicyInterface
|
||||
var labelsList []map[string]string
|
||||
var deleteDownstream bool
|
||||
|
@ -310,6 +308,12 @@ func (h *generationHandler) processRequest(ctx context.Context, policyContext *e
|
|||
}
|
||||
|
||||
pKey := common.PolicyKey(pNamespace, pName)
|
||||
urSpec := kyvernov2.UpdateRequestSpec{
|
||||
Type: kyvernov2.Generate,
|
||||
Policy: pKey,
|
||||
RuleContext: make([]kyvernov2.RuleContext, 0),
|
||||
}
|
||||
|
||||
for _, rule := range policy.GetSpec().Rules {
|
||||
if rule.Name == pRuleName && rule.Generation.Synchronize {
|
||||
gvk, subresource := policyContext.ResourceKind()
|
||||
|
@ -327,15 +331,16 @@ func (h *generationHandler) processRequest(ctx context.Context, policyContext *e
|
|||
continue
|
||||
}
|
||||
|
||||
ur := buildURSpec(kyvernov2.Generate, pKey, rule.Name, generateutils.TriggerFromLabels(labels), deleteDownstream)
|
||||
if err := h.urGenerator.Apply(ctx, ur); err != nil {
|
||||
e := event.NewBackgroundFailedEvent(err, policy, pRuleName, event.GeneratePolicyController,
|
||||
kyvernov1.ResourceSpec{Kind: new.GetKind(), Namespace: new.GetNamespace(), Name: new.GetName()})
|
||||
h.eventGen.Add(e...)
|
||||
return err
|
||||
}
|
||||
ruleCtx := buildRuleContext(rule, generateutils.TriggerFromLabels(labels), deleteDownstream)
|
||||
urSpec.RuleContext = append(urSpec.RuleContext, ruleCtx)
|
||||
}
|
||||
}
|
||||
if err := h.urGenerator.Apply(ctx, urSpec); err != nil {
|
||||
e := event.NewBackgroundFailedEvent(err, policy, "", event.GeneratePolicyController,
|
||||
kyvernov1.ResourceSpec{Kind: new.GetKind(), Namespace: new.GetNamespace(), Name: new.GetName()})
|
||||
h.eventGen.Add(e...)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,12 +7,23 @@ import (
|
|||
admissionv1 "k8s.io/api/admission/v1"
|
||||
)
|
||||
|
||||
func buildURSpec(requestType kyvernov2.RequestType, policyKey, ruleName string, resource kyvernov1.ResourceSpec, deleteDownstream bool) kyvernov2.UpdateRequestSpec {
|
||||
func buildURSpecNew(requestType kyvernov2.RequestType, policyKey string, rules []kyvernov1.Rule, trigger kyvernov1.ResourceSpec, deleteDownstream bool) kyvernov2.UpdateRequestSpec {
|
||||
ruleCtx := make([]kyvernov2.RuleContext, 0)
|
||||
for _, rule := range rules {
|
||||
ctx := buildRuleContext(rule, trigger, deleteDownstream)
|
||||
ruleCtx = append(ruleCtx, ctx)
|
||||
}
|
||||
return kyvernov2.UpdateRequestSpec{
|
||||
Type: requestType,
|
||||
Policy: policyKey,
|
||||
Rule: ruleName,
|
||||
Resource: resource,
|
||||
Type: requestType,
|
||||
Policy: policyKey,
|
||||
RuleContext: ruleCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func buildRuleContext(rule kyvernov1.Rule, trigger kyvernov1.ResourceSpec, deleteDownstream bool) kyvernov2.RuleContext {
|
||||
return kyvernov2.RuleContext{
|
||||
Rule: rule.Name,
|
||||
Trigger: trigger,
|
||||
DeleteDownstream: deleteDownstream,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ func (g *generator) tryApplyResource(ctx context.Context, urSpec kyvernov2.Updat
|
|||
if urSpec.GetRequestType() == kyvernov2.Mutate {
|
||||
queryLabels = common.MutateLabelsSet(urSpec.Policy, urSpec.GetResource())
|
||||
} else if urSpec.GetRequestType() == kyvernov2.Generate {
|
||||
queryLabels = common.GenerateLabelsSet(urSpec.Policy, urSpec.GetResource())
|
||||
queryLabels = common.GenerateLabelsSet(urSpec.Policy)
|
||||
}
|
||||
|
||||
l.V(4).Info("creating new UpdateRequest")
|
||||
|
|
|
@ -5,6 +5,8 @@ features:
|
|||
eventTypes: []
|
||||
|
||||
backgroundController:
|
||||
extraArgs:
|
||||
v: 4
|
||||
rbac:
|
||||
clusterRole:
|
||||
extraResources:
|
||||
|
|
|
@ -19,9 +19,15 @@ spec:
|
|||
try:
|
||||
- apply:
|
||||
file: trigger.yaml
|
||||
- name: step-03
|
||||
try:
|
||||
- sleep:
|
||||
duration: 2s
|
||||
- name: step-04
|
||||
try:
|
||||
- assert:
|
||||
file: target.yaml
|
||||
- name: step-03
|
||||
- name: step-05
|
||||
try:
|
||||
- delete:
|
||||
ref:
|
||||
|
@ -29,11 +35,11 @@ spec:
|
|||
kind: Secret
|
||||
name: mysecret
|
||||
namespace: clone-list-sync-same-trigger-source-trigger-ns
|
||||
- name: step-04
|
||||
- name: step-06
|
||||
try:
|
||||
- sleep:
|
||||
duration: 3s
|
||||
- name: step-05
|
||||
- name: step-07
|
||||
try:
|
||||
- error:
|
||||
file: target.yaml
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
## Description
|
||||
|
||||
This test ensures that a generate policy works as expected in case the rules have a different value for the `generateExisting` field.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
1. Create two Namespaces named `red-ns` and `green-ns`.
|
||||
|
||||
2. Create a policy with two generate rules:
|
||||
- The first rule named `generate-network-policy` matches Namespaces sets the `generateExisting` to `true`.
|
||||
- The second rule named `generate-config-map` matches Namespaces sets the `generateExisting` to `false`.
|
||||
|
||||
3. It is expected that a NetworkPolicy will be generated for each Namespace whereas ConfigMaps will not be generated.
|
||||
|
||||
## Reference Issue(s)
|
||||
|
||||
N/A
|
|
@ -0,0 +1,27 @@
|
|||
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||
kind: Test
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: different-generate-existing-values
|
||||
spec:
|
||||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: existing-resources.yaml
|
||||
- name: step-02
|
||||
try:
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
file: policy-ready.yaml
|
||||
- name: step-03
|
||||
try:
|
||||
- sleep:
|
||||
duration: 3s
|
||||
- name: step-04
|
||||
try:
|
||||
- assert:
|
||||
file: generated-resources.yaml
|
||||
- error:
|
||||
file: fail-generated-resources.yaml
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: red-ns
|
||||
labels:
|
||||
color: red
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: green-ns
|
||||
labels:
|
||||
color: green
|
|
@ -0,0 +1,34 @@
|
|||
apiVersion: v1
|
||||
data:
|
||||
KAFKA_ADDRESS: 192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092
|
||||
ZK_ADDRESS: 192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
somekey: somevalue
|
||||
name: zk-kafka-address
|
||||
namespace: red-ns
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
KAFKA_ADDRESS: 192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092
|
||||
ZK_ADDRESS: 192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
somekey: somevalue
|
||||
name: zk-kafka-address
|
||||
namespace: green-ns
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
labels:
|
||||
created-by: kyverno
|
||||
name: default-deny
|
||||
namespace: red-ns
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
labels:
|
||||
created-by: kyverno
|
||||
name: default-deny
|
||||
namespace: green-ns
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: different-generate-existing-values-reorder
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
|
@ -0,0 +1,53 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: different-generate-existing-values-reorder
|
||||
spec:
|
||||
rules:
|
||||
- name: generate-config-map
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Namespace
|
||||
names:
|
||||
- red-ns
|
||||
generate:
|
||||
generateExisting: false
|
||||
synchronize: true
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
name: zk-kafka-address
|
||||
namespace: "{{request.object.metadata.name}}"
|
||||
data:
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
somekey: somevalue
|
||||
data:
|
||||
ZK_ADDRESS: "192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181"
|
||||
KAFKA_ADDRESS: "192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092"
|
||||
- name: generate-network-policy
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Namespace
|
||||
names:
|
||||
- green-ns
|
||||
generate:
|
||||
generateExisting: true
|
||||
kind: NetworkPolicy
|
||||
apiVersion: networking.k8s.io/v1
|
||||
name: default-deny
|
||||
namespace: "{{request.object.metadata.name}}"
|
||||
synchronize: true
|
||||
data:
|
||||
metadata:
|
||||
labels:
|
||||
created-by: kyverno
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
|
@ -19,3 +19,16 @@ metadata:
|
|||
somekey: somevalue
|
||||
name: zk-kafka-address
|
||||
namespace: green-ns
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
labels:
|
||||
created-by: kyverno
|
||||
name: default-deny
|
||||
namespace: red-ns
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
|
|
|
@ -1,18 +1,5 @@
|
|||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
labels:
|
||||
created-by: kyverno
|
||||
name: default-deny
|
||||
namespace: red-ns
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
labels:
|
||||
created-by: kyverno
|
||||
|
|
|
@ -10,6 +10,8 @@ spec:
|
|||
- resources:
|
||||
kinds:
|
||||
- Namespace
|
||||
names:
|
||||
- green-ns
|
||||
generate:
|
||||
generateExisting: true
|
||||
kind: NetworkPolicy
|
||||
|
@ -32,6 +34,8 @@ spec:
|
|||
- resources:
|
||||
kinds:
|
||||
- Namespace
|
||||
names:
|
||||
- red-ns
|
||||
generate:
|
||||
generateExisting: false
|
||||
synchronize: true
|
||||
|
|
Loading…
Reference in a new issue