mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-05 15:37:19 +00:00
feat: add vpol status (#11956)
* feat: add vpol status Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: update status API Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: update code-gen manifests Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: reconcile vpol.status.conditions Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: add missing files Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: add default webhook filters Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: update codegen Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: update codegen Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: enable .status subresource Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: add missing files Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix: linter Signed-off-by: ShutingZhao <shuting@nirmata.com> --------- Signed-off-by: ShutingZhao <shuting@nirmata.com>
This commit is contained in:
parent
de71b19b6e
commit
1f3d82893b
19 changed files with 781 additions and 27 deletions
|
@ -2,12 +2,16 @@ package v2alpha1
|
|||
|
||||
import (
|
||||
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// +kubebuilder:object:generate=false
|
||||
type GenericPolicy interface {
|
||||
metav1.Object
|
||||
GetMatchConstraints() admissionregistrationv1.MatchResources
|
||||
GetMatchConditions() []admissionregistrationv1.MatchCondition
|
||||
GetFailurePolicy() admissionregistrationv1.FailurePolicyType
|
||||
GetWebhookConfiguration() *WebhookConfiguration
|
||||
GetVariables() []admissionregistrationv1.Variable
|
||||
GetStatus() *PolicyStatus
|
||||
}
|
||||
|
|
39
api/kyverno/v2alpha1/policy_status.go
Normal file
39
api/kyverno/v2alpha1/policy_status.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package v2alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type PolicyConditionType string
|
||||
|
||||
const (
|
||||
PolicyConditionTypeWebhookConfigured PolicyConditionType = "WebhookConfigured"
|
||||
PolicyConditionTypePolicyCached PolicyConditionType = "PolicyCached"
|
||||
PolicyConditionTypeRBACPermissionsGranted PolicyConditionType = "RBACPermissionsGranted"
|
||||
)
|
||||
|
||||
type PolicyStatus struct {
|
||||
// The ready of a policy is a high-level summary of where the policy is in its lifecycle.
|
||||
// The conditions array, the reason and message fields contain more detail about the policy's status.
|
||||
// +optional
|
||||
Ready bool `json:"ready,omitempty"`
|
||||
|
||||
// +optional
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
func (status *PolicyStatus) SetReadyByCondition(c PolicyConditionType, s metav1.ConditionStatus, message string) {
|
||||
reason := "Succeeded"
|
||||
if s != metav1.ConditionTrue {
|
||||
reason = "Failed"
|
||||
}
|
||||
newCondition := metav1.Condition{
|
||||
Type: string(c),
|
||||
Reason: reason,
|
||||
Status: s,
|
||||
Message: message,
|
||||
}
|
||||
|
||||
meta.SetStatusCondition(&status.Conditions, newCondition)
|
||||
}
|
|
@ -8,13 +8,18 @@ import (
|
|||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:resource:path=validatingpolicies,scope="Cluster",shortName=vpol,categories=kyverno
|
||||
// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
type ValidatingPolicy struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
Spec ValidatingPolicySpec `json:"spec"`
|
||||
// Status contains policy runtime data.
|
||||
// +optional
|
||||
Status PolicyStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (s *ValidatingPolicy) GetMatchConstraints() admissionregistrationv1.MatchResources {
|
||||
|
@ -32,10 +37,18 @@ func (s *ValidatingPolicy) GetFailurePolicy() admissionregistrationv1.FailurePol
|
|||
return *s.Spec.FailurePolicy
|
||||
}
|
||||
|
||||
func (s *ValidatingPolicy) GetWebhookConfiguration() *WebhookConfiguration {
|
||||
return s.Spec.WebhookConfiguration
|
||||
}
|
||||
|
||||
func (s *ValidatingPolicy) GetVariables() []admissionregistrationv1.Variable {
|
||||
return s.Spec.Variables
|
||||
}
|
||||
|
||||
func (s *ValidatingPolicy) GetStatus() *PolicyStatus {
|
||||
return &s.Status
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
|
|
|
@ -288,12 +288,36 @@ func (in *PolicyRef) DeepCopy() *PolicyRef {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PolicyStatus) DeepCopyInto(out *PolicyStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]metav1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyStatus.
|
||||
func (in *PolicyStatus) DeepCopy() *PolicyStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PolicyStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ValidatingPolicy) DeepCopyInto(out *ValidatingPolicy) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,11 @@ spec:
|
|||
singular: validatingpolicy
|
||||
scope: Cluster
|
||||
versions:
|
||||
- name: v2alpha1
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: AGE
|
||||
type: date
|
||||
name: v2alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
|
@ -682,9 +686,76 @@ spec:
|
|||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
status:
|
||||
description: Status contains policy runtime data.
|
||||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
ready:
|
||||
description: |-
|
||||
The ready of a policy is a high-level summary of where the policy is in its lifecycle.
|
||||
The conditions array, the reason and message fields contain more detail about the policy's status.
|
||||
type: boolean
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
{{- end }}
|
||||
|
|
|
@ -18,7 +18,11 @@ spec:
|
|||
singular: validatingpolicy
|
||||
scope: Cluster
|
||||
versions:
|
||||
- name: v2alpha1
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: AGE
|
||||
type: date
|
||||
name: v2alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
|
@ -676,8 +680,75 @@ spec:
|
|||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
status:
|
||||
description: Status contains policy runtime data.
|
||||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
ready:
|
||||
description: |-
|
||||
The ready of a policy is a high-level summary of where the policy is in its lifecycle.
|
||||
The conditions array, the reason and message fields contain more detail about the policy's status.
|
||||
type: boolean
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
|
|
|
@ -18,7 +18,11 @@ spec:
|
|||
singular: validatingpolicy
|
||||
scope: Cluster
|
||||
versions:
|
||||
- name: v2alpha1
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: AGE
|
||||
type: date
|
||||
name: v2alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
|
@ -676,8 +680,75 @@ spec:
|
|||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
status:
|
||||
description: Status contains policy runtime data.
|
||||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
ready:
|
||||
description: |-
|
||||
The ready of a policy is a high-level summary of where the policy is in its lifecycle.
|
||||
The conditions array, the reason and message fields contain more detail about the policy's status.
|
||||
type: boolean
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
|
|
|
@ -48885,7 +48885,11 @@ spec:
|
|||
singular: validatingpolicy
|
||||
scope: Cluster
|
||||
versions:
|
||||
- name: v2alpha1
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: AGE
|
||||
type: date
|
||||
name: v2alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
|
@ -49543,11 +49547,78 @@ spec:
|
|||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
status:
|
||||
description: Status contains policy runtime data.
|
||||
properties:
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
state of this API Resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: |-
|
||||
lastTransitionTime is the last time the condition transitioned from one status to another.
|
||||
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message is a human readable message indicating details about the transition.
|
||||
This may be an empty string.
|
||||
maxLength: 32768
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: |-
|
||||
observedGeneration represents the .metadata.generation that the condition was set based upon.
|
||||
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
|
||||
with respect to the current state of the instance.
|
||||
format: int64
|
||||
minimum: 0
|
||||
type: integer
|
||||
reason:
|
||||
description: |-
|
||||
reason contains a programmatic identifier indicating the reason for the condition's last transition.
|
||||
Producers of specific condition types may define expected values and meanings for this field,
|
||||
and whether the values are considered a guaranteed API.
|
||||
The value should be a CamelCase string.
|
||||
This field may not be empty.
|
||||
maxLength: 1024
|
||||
minLength: 1
|
||||
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||
type: string
|
||||
status:
|
||||
description: status of the condition, one of True, False, Unknown.
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type: string
|
||||
type:
|
||||
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||
maxLength: 316
|
||||
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- message
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
ready:
|
||||
description: |-
|
||||
The ready of a policy is a high-level summary of where the policy is in its lifecycle.
|
||||
The conditions array, the reason and message fields contain more detail about the policy's status.
|
||||
type: boolean
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
|
|
|
@ -7580,6 +7580,20 @@ WebhookConfiguration
|
|||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>status</code><br/>
|
||||
<em>
|
||||
<a href="#kyverno.io/v2alpha1.PolicyStatus">
|
||||
PolicyStatus
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Status contains policy runtime data.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
|
@ -7884,6 +7898,10 @@ If left empty for namespaced resources, all resources from all namespaces will b
|
|||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v2alpha1.PolicyConditionType">PolicyConditionType
|
||||
(<code>string</code> alias)</p></h3>
|
||||
<p>
|
||||
</p>
|
||||
<h3 id="kyverno.io/v2alpha1.PolicyRef">PolicyRef
|
||||
</h3>
|
||||
<p>
|
||||
|
@ -7925,6 +7943,51 @@ string
|
|||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v2alpha1.PolicyStatus">PolicyStatus
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kyverno.io/v2alpha1.ValidatingPolicy">ValidatingPolicy</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>ready</code><br/>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>The ready of a policy is a high-level summary of where the policy is in its lifecycle.
|
||||
The conditions array, the reason and message fields contain more detail about the policy’s status.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>conditions</code><br/>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#condition-v1-meta">
|
||||
[]Kubernetes meta/v1.Condition
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v2alpha1.ValidatingPolicySpec">ValidatingPolicySpec
|
||||
</h3>
|
||||
<p>
|
||||
|
|
|
@ -649,6 +649,35 @@ Required.</p>
|
|||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
<td><code>status</code>
|
||||
|
||||
</br>
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="#kyverno-io-v2alpha1-PolicyStatus">
|
||||
<span style="font-family: monospace">PolicyStatus</span>
|
||||
</a>
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
|
||||
<p>Status contains policy runtime data.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
</tbody>
|
||||
|
@ -1361,6 +1390,95 @@ If left empty for namespaced resources, all resources from all namespaces will b
|
|||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<H3 id="kyverno-io-v2alpha1-PolicyStatus">PolicyStatus
|
||||
</H3>
|
||||
|
||||
|
||||
<p>
|
||||
(<em>Appears in:</em>
|
||||
<a href="#kyverno-io-v2alpha1-ValidatingPolicy">ValidatingPolicy</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>ready</code>
|
||||
|
||||
</br>
|
||||
|
||||
|
||||
|
||||
|
||||
<span style="font-family: monospace">bool</span>
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
|
||||
<p>The ready of a policy is a high-level summary of where the policy is in its lifecycle.
|
||||
The conditions array, the reason and message fields contain more detail about the policy's status.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
<td><code>conditions</code>
|
||||
|
||||
</br>
|
||||
|
||||
|
||||
|
||||
|
||||
<span style="font-family: monospace">[]meta/v1.Condition</span>
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
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 v2alpha1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// PolicyStatusApplyConfiguration represents an declarative configuration of the PolicyStatus type for use
|
||||
// with apply.
|
||||
type PolicyStatusApplyConfiguration struct {
|
||||
Ready *bool `json:"ready,omitempty"`
|
||||
Conditions []v1.Condition `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
// PolicyStatusApplyConfiguration constructs an declarative configuration of the PolicyStatus type for use with
|
||||
// apply.
|
||||
func PolicyStatus() *PolicyStatusApplyConfiguration {
|
||||
return &PolicyStatusApplyConfiguration{}
|
||||
}
|
||||
|
||||
// WithReady sets the Ready 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 Ready field is set to the value of the last call.
|
||||
func (b *PolicyStatusApplyConfiguration) WithReady(value bool) *PolicyStatusApplyConfiguration {
|
||||
b.Ready = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithConditions adds the given value to the Conditions 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 Conditions field.
|
||||
func (b *PolicyStatusApplyConfiguration) WithConditions(values ...v1.Condition) *PolicyStatusApplyConfiguration {
|
||||
for i := range values {
|
||||
b.Conditions = append(b.Conditions, values[i])
|
||||
}
|
||||
return b
|
||||
}
|
|
@ -30,6 +30,7 @@ type ValidatingPolicyApplyConfiguration struct {
|
|||
v1.TypeMetaApplyConfiguration `json:",inline"`
|
||||
*v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"`
|
||||
Spec *ValidatingPolicySpecApplyConfiguration `json:"spec,omitempty"`
|
||||
Status *PolicyStatusApplyConfiguration `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// ValidatingPolicy constructs an declarative configuration of the ValidatingPolicy type for use with
|
||||
|
@ -207,3 +208,11 @@ func (b *ValidatingPolicyApplyConfiguration) WithSpec(value *ValidatingPolicySpe
|
|||
b.Spec = value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithStatus sets the Status 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 Status field is set to the value of the last call.
|
||||
func (b *ValidatingPolicyApplyConfiguration) WithStatus(value *PolicyStatusApplyConfiguration) *ValidatingPolicyApplyConfiguration {
|
||||
b.Status = value
|
||||
return b
|
||||
}
|
||||
|
|
|
@ -223,6 +223,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
|||
return &kyvernov2alpha1.KubernetesResourceApplyConfiguration{}
|
||||
case v2alpha1.SchemeGroupVersion.WithKind("PolicyRef"):
|
||||
return &kyvernov2alpha1.PolicyRefApplyConfiguration{}
|
||||
case v2alpha1.SchemeGroupVersion.WithKind("PolicyStatus"):
|
||||
return &kyvernov2alpha1.PolicyStatusApplyConfiguration{}
|
||||
case v2alpha1.SchemeGroupVersion.WithKind("ValidatingPolicy"):
|
||||
return &kyvernov2alpha1.ValidatingPolicyApplyConfiguration{}
|
||||
case v2alpha1.SchemeGroupVersion.WithKind("ValidatingPolicySpec"):
|
||||
|
|
|
@ -95,6 +95,17 @@ func (c *FakeValidatingPolicies) Update(ctx context.Context, validatingPolicy *v
|
|||
return obj.(*v2alpha1.ValidatingPolicy), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeValidatingPolicies) UpdateStatus(ctx context.Context, validatingPolicy *v2alpha1.ValidatingPolicy, opts v1.UpdateOptions) (*v2alpha1.ValidatingPolicy, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateSubresourceAction(validatingpoliciesResource, "status", validatingPolicy), &v2alpha1.ValidatingPolicy{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v2alpha1.ValidatingPolicy), err
|
||||
}
|
||||
|
||||
// Delete takes name of the validatingPolicy and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeValidatingPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
|
|
|
@ -40,6 +40,7 @@ type ValidatingPoliciesGetter interface {
|
|||
type ValidatingPolicyInterface interface {
|
||||
Create(ctx context.Context, validatingPolicy *v2alpha1.ValidatingPolicy, opts v1.CreateOptions) (*v2alpha1.ValidatingPolicy, error)
|
||||
Update(ctx context.Context, validatingPolicy *v2alpha1.ValidatingPolicy, opts v1.UpdateOptions) (*v2alpha1.ValidatingPolicy, error)
|
||||
UpdateStatus(ctx context.Context, validatingPolicy *v2alpha1.ValidatingPolicy, opts v1.UpdateOptions) (*v2alpha1.ValidatingPolicy, error)
|
||||
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v2alpha1.ValidatingPolicy, error)
|
||||
|
@ -128,6 +129,21 @@ func (c *validatingPolicies) Update(ctx context.Context, validatingPolicy *v2alp
|
|||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *validatingPolicies) UpdateStatus(ctx context.Context, validatingPolicy *v2alpha1.ValidatingPolicy, opts v1.UpdateOptions) (result *v2alpha1.ValidatingPolicy, err error) {
|
||||
result = &v2alpha1.ValidatingPolicy{}
|
||||
err = c.client.Put().
|
||||
Resource("validatingpolicies").
|
||||
Name(validatingPolicy.Name).
|
||||
SubResource("status").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(validatingPolicy).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the validatingPolicy and deletes it. Returns an error if one occurs.
|
||||
func (c *validatingPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
|
|
|
@ -111,6 +111,17 @@ func (c *withLogging) Update(arg0 context.Context, arg1 *github_com_kyverno_kyve
|
|||
}
|
||||
return ret0, ret1
|
||||
}
|
||||
func (c *withLogging) UpdateStatus(arg0 context.Context, arg1 *github_com_kyverno_kyverno_api_kyverno_v2alpha1.ValidatingPolicy, arg2 k8s_io_apimachinery_pkg_apis_meta_v1.UpdateOptions) (*github_com_kyverno_kyverno_api_kyverno_v2alpha1.ValidatingPolicy, error) {
|
||||
start := time.Now()
|
||||
logger := c.logger.WithValues("operation", "UpdateStatus")
|
||||
ret0, ret1 := c.inner.UpdateStatus(arg0, arg1, arg2)
|
||||
if err := multierr.Combine(ret1); err != nil {
|
||||
logger.Error(err, "UpdateStatus failed", "duration", time.Since(start))
|
||||
} else {
|
||||
logger.Info("UpdateStatus done", "duration", time.Since(start))
|
||||
}
|
||||
return ret0, ret1
|
||||
}
|
||||
func (c *withLogging) Watch(arg0 context.Context, arg1 k8s_io_apimachinery_pkg_apis_meta_v1.ListOptions) (k8s_io_apimachinery_pkg_watch.Interface, error) {
|
||||
start := time.Now()
|
||||
logger := c.logger.WithValues("operation", "Watch")
|
||||
|
@ -156,6 +167,10 @@ func (c *withMetrics) Update(arg0 context.Context, arg1 *github_com_kyverno_kyve
|
|||
defer c.recorder.RecordWithContext(arg0, "update")
|
||||
return c.inner.Update(arg0, arg1, arg2)
|
||||
}
|
||||
func (c *withMetrics) UpdateStatus(arg0 context.Context, arg1 *github_com_kyverno_kyverno_api_kyverno_v2alpha1.ValidatingPolicy, arg2 k8s_io_apimachinery_pkg_apis_meta_v1.UpdateOptions) (*github_com_kyverno_kyverno_api_kyverno_v2alpha1.ValidatingPolicy, error) {
|
||||
defer c.recorder.RecordWithContext(arg0, "update_status")
|
||||
return c.inner.UpdateStatus(arg0, arg1, arg2)
|
||||
}
|
||||
func (c *withMetrics) Watch(arg0 context.Context, arg1 k8s_io_apimachinery_pkg_apis_meta_v1.ListOptions) (k8s_io_apimachinery_pkg_watch.Interface, error) {
|
||||
defer c.recorder.RecordWithContext(arg0, "watch")
|
||||
return c.inner.Watch(arg0, arg1)
|
||||
|
@ -314,6 +329,27 @@ func (c *withTracing) Update(arg0 context.Context, arg1 *github_com_kyverno_kyve
|
|||
}
|
||||
return ret0, ret1
|
||||
}
|
||||
func (c *withTracing) UpdateStatus(arg0 context.Context, arg1 *github_com_kyverno_kyverno_api_kyverno_v2alpha1.ValidatingPolicy, arg2 k8s_io_apimachinery_pkg_apis_meta_v1.UpdateOptions) (*github_com_kyverno_kyverno_api_kyverno_v2alpha1.ValidatingPolicy, error) {
|
||||
var span trace.Span
|
||||
if tracing.IsInSpan(arg0) {
|
||||
arg0, span = tracing.StartChildSpan(
|
||||
arg0,
|
||||
"",
|
||||
fmt.Sprintf("KUBE %s/%s/%s", c.client, c.kind, "UpdateStatus"),
|
||||
trace.WithAttributes(
|
||||
tracing.KubeClientGroupKey.String(c.client),
|
||||
tracing.KubeClientKindKey.String(c.kind),
|
||||
tracing.KubeClientOperationKey.String("UpdateStatus"),
|
||||
),
|
||||
)
|
||||
defer span.End()
|
||||
}
|
||||
ret0, ret1 := c.inner.UpdateStatus(arg0, arg1, arg2)
|
||||
if span != nil {
|
||||
tracing.SetSpanStatus(span, ret1)
|
||||
}
|
||||
return ret0, ret1
|
||||
}
|
||||
func (c *withTracing) Watch(arg0 context.Context, arg1 k8s_io_apimachinery_pkg_apis_meta_v1.ListOptions) (k8s_io_apimachinery_pkg_watch.Interface, error) {
|
||||
var span trace.Span
|
||||
if tracing.IsInSpan(arg0) {
|
||||
|
|
|
@ -126,6 +126,10 @@ type controller struct {
|
|||
// state
|
||||
lock sync.Mutex
|
||||
policyState map[string]sets.Set[string]
|
||||
|
||||
// vpolState records validatingpolicies that are configured
|
||||
// successfully in webhook object, non-thread safe
|
||||
vpolState map[string]bool
|
||||
}
|
||||
|
||||
func NewController(
|
||||
|
@ -193,6 +197,7 @@ func NewController(
|
|||
config.MutatingWebhookConfigurationName: sets.New[string](),
|
||||
config.ValidatingWebhookConfigurationName: sets.New[string](),
|
||||
},
|
||||
vpolState: make(map[string]bool),
|
||||
}
|
||||
if _, _, err := controllerutils.AddDefaultEventHandlers(logger, mwcInformer.Informer(), queue); err != nil {
|
||||
logger.Error(err, "failed to register event handlers")
|
||||
|
@ -376,6 +381,13 @@ func (c *controller) recordPolicyState(webhookConfigurationName string, policies
|
|||
}
|
||||
}
|
||||
|
||||
func (c *controller) recordValidatingPolicyState(validatingpolicies ...kyvernov2alpha1.GenericPolicy) {
|
||||
c.vpolState = make(map[string]bool)
|
||||
for _, policy := range validatingpolicies {
|
||||
c.vpolState[policy.GetName()] = true
|
||||
}
|
||||
}
|
||||
|
||||
func (c *controller) reconcileResourceValidatingWebhookConfiguration(ctx context.Context) error {
|
||||
if c.autoUpdateWebhooks {
|
||||
return c.reconcileValidatingWebhookConfiguration(ctx, c.autoUpdateWebhooks, c.buildResourceValidatingWebhookConfiguration)
|
||||
|
@ -642,6 +654,41 @@ func (c *controller) updatePolicyStatuses(ctx context.Context, webhookType strin
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) updateValidatingPolicyStatuses(ctx context.Context) error {
|
||||
vpols, err := c.getValidatingPolicies()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updateStatusFunc := func(vpol kyvernov2alpha1.GenericPolicy) error {
|
||||
status := vpol.GetStatus()
|
||||
status.SetReadyByCondition(kyvernov2alpha1.PolicyConditionTypeWebhookConfigured, metav1.ConditionTrue, "Webhook configured")
|
||||
return nil
|
||||
}
|
||||
|
||||
var errs []error
|
||||
for _, vpol := range vpols {
|
||||
if !c.vpolState[vpol.GetName()] {
|
||||
continue
|
||||
}
|
||||
err := controllerutils.UpdateStatus(
|
||||
ctx,
|
||||
vpol.(*kyvernov2alpha1.ValidatingPolicy),
|
||||
c.kyvernoClient.KyvernoV2alpha1().ValidatingPolicies(),
|
||||
func(vpol *kyvernov2alpha1.ValidatingPolicy) error {
|
||||
return updateStatusFunc(vpol)
|
||||
},
|
||||
func(a *kyvernov2alpha1.ValidatingPolicy, b *kyvernov2alpha1.ValidatingPolicy) bool {
|
||||
return datautils.DeepEqual(a.Status, b.Status)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("%s: %w", vpol.GetName(), err))
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
|
||||
func (c *controller) reconcile(ctx context.Context, logger logr.Logger, key, namespace, name string) error {
|
||||
if c.autoDeleteWebhooks && c.runtime.IsGoingDown() {
|
||||
return c.reconcileWebhookDeletion(ctx)
|
||||
|
@ -666,9 +713,16 @@ func (c *controller) reconcile(ctx context.Context, logger logr.Logger, key, nam
|
|||
if err := c.reconcileResourceValidatingWebhookConfiguration(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var errs []error
|
||||
if err := c.updatePolicyStatuses(ctx, config.ValidatingWebhookConfigurationName); err != nil {
|
||||
return err
|
||||
errs = append(errs, fmt.Errorf("failed to update policy statuses: %w", err))
|
||||
}
|
||||
|
||||
if err := c.updateValidatingPolicyStatuses(ctx); err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed to update validating policy statuses: %w", err))
|
||||
}
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
case config.PolicyValidatingWebhookConfigurationName:
|
||||
return c.reconcilePolicyValidatingWebhookConfiguration(ctx)
|
||||
|
@ -953,25 +1007,26 @@ func (c *controller) buildResourceValidatingWebhookConfiguration(ctx context.Con
|
|||
errs = append(errs, fmt.Errorf("failed to build webhook rules for policies: %v", err))
|
||||
}
|
||||
|
||||
if err := c.buildForValidatingPolicies(ctx, cfg, caBundle, webhookConfig); err != nil {
|
||||
if err := c.buildForValidatingPolicies(cfg, caBundle, webhookConfig); err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed to build webhook rules for validatingpolicies: %v", err))
|
||||
}
|
||||
|
||||
return webhookConfig, multierr.Combine(errs...)
|
||||
}
|
||||
|
||||
func (c *controller) buildForValidatingPolicies(ctx context.Context, cfg config.Configuration, caBundle []byte, result *admissionregistrationv1.ValidatingWebhookConfiguration) error {
|
||||
func (c *controller) buildForValidatingPolicies(cfg config.Configuration, caBundle []byte, result *admissionregistrationv1.ValidatingWebhookConfiguration) error {
|
||||
if !c.watchdogCheck() {
|
||||
return nil
|
||||
}
|
||||
|
||||
vpols, err := c.vpolLister.List(labels.Everything())
|
||||
vpols, err := c.getValidatingPolicies()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
webhooks := buildWebhookRules(c.server, c.servicePort, caBundle, vpols)
|
||||
webhooks := buildWebhookRules(cfg, c.server, c.servicePort, caBundle, vpols)
|
||||
result.Webhooks = append(result.Webhooks, webhooks...)
|
||||
c.recordValidatingPolicyState(vpols...)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1020,7 +1075,7 @@ func (c *controller) buildForPolicies(ctx context.Context, cfg config.Configurat
|
|||
webhooks = append(webhooks, fineGrainedFailList...)
|
||||
result.Webhooks = c.buildResourceValidatingWebhookRules(caBundle, webhookCfg, sideEffects, webhooks)
|
||||
} else {
|
||||
c.recordPolicyState(config.MutatingWebhookConfigurationName)
|
||||
c.recordPolicyState(config.ValidatingWebhookConfigurationName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1077,6 +1132,19 @@ func (c *controller) getAllPolicies() ([]kyvernov1.PolicyInterface, error) {
|
|||
return policies, nil
|
||||
}
|
||||
|
||||
func (c *controller) getValidatingPolicies() ([]kyvernov2alpha1.GenericPolicy, error) {
|
||||
validatingpolicies, err := c.vpolLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vpols := make([]kyvernov2alpha1.GenericPolicy, 0)
|
||||
for _, vpol := range validatingpolicies {
|
||||
vpols = append(vpols, vpol)
|
||||
}
|
||||
return vpols, nil
|
||||
}
|
||||
|
||||
func (c *controller) getLease() (*coordinationv1.Lease, error) {
|
||||
return c.leaseLister.Leases(config.KyvernoNamespace()).Get("kyverno-health")
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
func buildWebhookRules(server string, servicePort int32, caBundle []byte, vpols []*kyvernov2alpha1.ValidatingPolicy) (webhooks []admissionregistrationv1.ValidatingWebhook) {
|
||||
func buildWebhookRules(cfg config.Configuration, server string, servicePort int32, caBundle []byte, vpols []kyvernov2alpha1.GenericPolicy) (webhooks []admissionregistrationv1.ValidatingWebhook) {
|
||||
var (
|
||||
webhookIgnoreList []admissionregistrationv1.ValidatingWebhook
|
||||
webhookFailList []admissionregistrationv1.ValidatingWebhook
|
||||
|
@ -26,30 +26,39 @@ func buildWebhookRules(server string, servicePort int32, caBundle []byte, vpols
|
|||
AdmissionReviewVersions: []string{"v1"},
|
||||
}
|
||||
)
|
||||
|
||||
if cfg.GetWebhook().NamespaceSelector != nil {
|
||||
webhookIgnore.NamespaceSelector = cfg.GetWebhook().NamespaceSelector
|
||||
webhookFail.NamespaceSelector = cfg.GetWebhook().NamespaceSelector
|
||||
}
|
||||
if cfg.GetWebhook().ObjectSelector != nil {
|
||||
webhookIgnore.ObjectSelector = cfg.GetWebhook().ObjectSelector
|
||||
webhookFail.ObjectSelector = cfg.GetWebhook().ObjectSelector
|
||||
}
|
||||
for _, vpol := range vpols {
|
||||
webhook := admissionregistrationv1.ValidatingWebhook{}
|
||||
failurePolicyIgnore := vpol.Spec.FailurePolicy != nil && *vpol.Spec.FailurePolicy == admissionregistrationv1.Ignore
|
||||
failurePolicyIgnore := vpol.GetFailurePolicy() == admissionregistrationv1.Ignore
|
||||
if failurePolicyIgnore {
|
||||
webhook.FailurePolicy = ptr.To(admissionregistrationv1.Ignore)
|
||||
} else {
|
||||
webhook.FailurePolicy = ptr.To(admissionregistrationv1.Fail)
|
||||
}
|
||||
// TODO(shuting): exclude?
|
||||
for _, match := range vpol.Spec.MatchConstraints.ResourceRules {
|
||||
for _, match := range vpol.GetMatchConstraints().ResourceRules {
|
||||
webhook.Rules = append(webhook.Rules, match.RuleWithOperations)
|
||||
}
|
||||
|
||||
fineGrainedWebhook := false
|
||||
if vpol.Spec.MatchConditions != nil {
|
||||
webhook.MatchConditions = vpol.Spec.MatchConditions
|
||||
if vpol.GetMatchConditions() != nil {
|
||||
webhook.MatchConditions = vpol.GetMatchConditions()
|
||||
fineGrainedWebhook = true
|
||||
}
|
||||
if vpol.Spec.MatchConstraints.MatchPolicy != nil && *vpol.Spec.MatchConstraints.MatchPolicy == admissionregistrationv1.Exact {
|
||||
webhook.MatchPolicy = vpol.Spec.MatchConstraints.MatchPolicy
|
||||
if vpol.GetMatchConstraints().MatchPolicy != nil && *vpol.GetMatchConstraints().MatchPolicy == admissionregistrationv1.Exact {
|
||||
webhook.MatchPolicy = vpol.GetMatchConstraints().MatchPolicy
|
||||
fineGrainedWebhook = true
|
||||
}
|
||||
if vpol.Spec.WebhookConfiguration != nil && vpol.Spec.WebhookConfiguration.TimeoutSeconds != nil {
|
||||
webhook.TimeoutSeconds = vpol.Spec.WebhookConfiguration.TimeoutSeconds
|
||||
if vpol.GetWebhookConfiguration() != nil && vpol.GetWebhookConfiguration().TimeoutSeconds != nil {
|
||||
webhook.TimeoutSeconds = vpol.GetWebhookConfiguration().TimeoutSeconds
|
||||
fineGrainedWebhook = true
|
||||
}
|
||||
|
||||
|
@ -57,12 +66,12 @@ func buildWebhookRules(server string, servicePort int32, caBundle []byte, vpols
|
|||
webhook.SideEffects = &noneOnDryRun
|
||||
webhook.AdmissionReviewVersions = []string{"v1"}
|
||||
if failurePolicyIgnore {
|
||||
webhook.Name = config.ValidatingPolicyWebhookName + "-ignore-finegrained-" + vpol.Name
|
||||
webhook.ClientConfig = newClientConfig(server, servicePort, caBundle, config.ValidatingPolicyServicePath+"/ignore"+config.FineGrainedWebhookPath+"/"+vpol.Name)
|
||||
webhook.Name = config.ValidatingPolicyWebhookName + "-ignore-finegrained-" + vpol.GetName()
|
||||
webhook.ClientConfig = newClientConfig(server, servicePort, caBundle, "/validate/ignore"+config.FineGrainedWebhookPath+"/"+vpol.GetName())
|
||||
webhookIgnoreList = append(webhookIgnoreList, webhook)
|
||||
} else {
|
||||
webhook.Name = config.ValidatingPolicyWebhookName + "-fail-finegrained-" + vpol.Name
|
||||
webhook.ClientConfig = newClientConfig(server, servicePort, caBundle, config.ValidatingPolicyServicePath+"/fail"+config.FineGrainedWebhookPath+"/"+vpol.Name)
|
||||
webhook.Name = config.ValidatingPolicyWebhookName + "-fail-finegrained-" + vpol.GetName()
|
||||
webhook.ClientConfig = newClientConfig(server, servicePort, caBundle, "/validate/fail"+config.FineGrainedWebhookPath+"/"+vpol.GetName())
|
||||
webhookFailList = append(webhookFailList, webhook)
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -141,7 +141,7 @@ func TestBuildWebhookRules(t *testing.T) {
|
|||
expectedWebhooks: []admissionregistrationv1.ValidatingWebhook{
|
||||
{
|
||||
Name: config.ValidatingPolicyWebhookName + "-ignore-finegrained-test-fine-grained-ignore",
|
||||
ClientConfig: newClientConfig("", 0, nil, config.ValidatingPolicyServicePath+"/ignore"+config.FineGrainedWebhookPath+"/test-fine-grained-ignore"),
|
||||
ClientConfig: newClientConfig("", 0, nil, "/validate/ignore"+config.FineGrainedWebhookPath+"/test-fine-grained-ignore"),
|
||||
Rules: []admissionregistrationv1.RuleWithOperations{
|
||||
{
|
||||
Operations: []admissionregistrationv1.OperationType{admissionregistrationv1.Create},
|
||||
|
@ -201,7 +201,7 @@ func TestBuildWebhookRules(t *testing.T) {
|
|||
expectedWebhooks: []admissionregistrationv1.ValidatingWebhook{
|
||||
{
|
||||
Name: config.ValidatingPolicyWebhookName + "-fail-finegrained-test-fine-grained-fail",
|
||||
ClientConfig: newClientConfig("", 0, nil, config.ValidatingPolicyServicePath+"/fail"+config.FineGrainedWebhookPath+"/test-fine-grained-fail"),
|
||||
ClientConfig: newClientConfig("", 0, nil, "/validate/fail"+config.FineGrainedWebhookPath+"/test-fine-grained-fail"),
|
||||
Rules: []admissionregistrationv1.RuleWithOperations{
|
||||
{
|
||||
Operations: []admissionregistrationv1.OperationType{admissionregistrationv1.Create},
|
||||
|
@ -229,7 +229,11 @@ func TestBuildWebhookRules(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
webhooks := buildWebhookRules("", 0, nil, tt.vpols)
|
||||
var vpols []kyvernov2alpha1.GenericPolicy
|
||||
for _, vpol := range tt.vpols {
|
||||
vpols = append(vpols, vpol)
|
||||
}
|
||||
webhooks := buildWebhookRules(config.NewDefaultConfiguration(false), "", 0, nil, vpols)
|
||||
assert.Equal(t, len(tt.expectedWebhooks), len(webhooks))
|
||||
for i, expect := range tt.expectedWebhooks {
|
||||
assert.Equal(t, expect.Name, webhooks[i].Name)
|
||||
|
@ -246,7 +250,7 @@ func TestBuildWebhookRules(t *testing.T) {
|
|||
assert.Equal(t, expect.TimeoutSeconds, webhooks[i].TimeoutSeconds)
|
||||
}
|
||||
if expect.ClientConfig.Service != nil {
|
||||
assert.Equal(t, expect.ClientConfig.Service.Path, webhooks[i].ClientConfig.Service.Path)
|
||||
assert.Equal(t, *webhooks[i].ClientConfig.Service.Path, *expect.ClientConfig.Service.Path)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Add table
Reference in a new issue