Skip to content

Commit 3a08b40

Browse files
committed
convert some override webhook logic to CEL & add tests
Signed-off-by: Britania Rodriguez Reyes <[email protected]>
1 parent d5e3c48 commit 3a08b40

19 files changed

+950
-20
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Breadcrumb for CEL Conversion: ClusterResourceOverride
2+
3+
## Requirements
4+
- Convert webhook validation logic for ClusterResourceOverride to CEL XValidation rules in the CRD.
5+
- Remove/replace webhook logic that is now enforced by CEL.
6+
- Ensure all constraints that can be enforced by CEL are migrated.
7+
- Document what remains in webhook (cross-object checks).
8+
9+
## Additional comments from user
10+
- User approved the plan to proceed with CEL conversion for ClusterResourceOverride.
11+
12+
## Plan
13+
### Phase 1: Analyze and Write CEL Expressions
14+
- [ ] Task 1.1: Identify all webhook validation logic that can be enforced by CEL.
15+
- [ ] Task 1.2: Write CEL XValidation rules for:
16+
- No labelSelector in clusterResourceSelectors
17+
- Name is required in clusterResourceSelectors
18+
- No duplicate clusterResourceSelectors
19+
- [ ] Task 1.3: Add CEL rules to the CRD YAML.
20+
21+
### Phase 2: Remove/Refactor Webhook Logic
22+
- [ ] Task 2.1: Remove/replace Go validation logic now enforced by CEL.
23+
- [ ] Task 2.2: Update webhook to only perform cross-object checks (e.g., uniqueness across objects).
24+
25+
### Phase 3: Test and Document
26+
- [ ] Task 3.1: Test CRD validation with CEL rules.
27+
- [ ] Task 3.2: Update documentation and this breadcrumb with before/after comparison.
28+
29+
## Decisions
30+
- CEL will be used for all per-object validation that does not require access to other objects.
31+
- Webhook will remain for cross-object uniqueness checks.
32+
33+
## Implementation Details
34+
- CEL rules will be added under `x-kubernetes-validations` in the CRD.
35+
- Go code will be refactored to avoid duplicate validation.
36+
37+
## Changes Made
38+
- (To be updated after implementation)
39+
40+
## Before/After Comparison
41+
- (To be updated after implementation)
42+
43+
## References
44+
- `/pkg/utils/validator/clusterresourceoverride.go` (Go validation logic)
45+
- `/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceoverrides.yaml` (CRD definition)
46+
- [Kubernetes CEL docs](https://kubernetes.io/docs/reference/using-api/cel/)

apis/cluster/v1beta1/zz_generated.deepcopy.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apis/placement/v1alpha1/override_types.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
66
You may obtain a copy of the License at
77
8-
http://www.apache.org/licenses/LICENSE-2.0
8+
http://www.apache.org/licenses/LICENSE-2.0
99
1010
Unless required by applicable law or agreed to in writing, software
1111
distributed under the License is distributed on an "AS IS" BASIS,
@@ -91,6 +91,8 @@ type OverridePolicy struct {
9191
}
9292

9393
// OverrideRule defines how to override the selected resources on the target clusters.
94+
// +kubebuilder:validation:XValidation:rule="!(has(self.overrideType) && self.overrideType == 'Delete' && self.jsonPatchOverrides.size() != 0)", message="jsonPatchOverrides cannot be set when the override type is Delete."
95+
// +kubebuilder:validation:XValidation:rule="!(has(self.overrideType) && self.overrideType == 'JSONPatch' && self.jsonPatchOverrides.size() == 0)", message="jsonPatchOverrides must be set when the override type is JSONPatch."
9496
type OverrideRule struct {
9597
// ClusterSelectors selects the target clusters.
9698
// The resources will be overridden before applying to the matching clusters.
@@ -198,6 +200,10 @@ type JSONPatchOverride struct {
198200
// Path defines the target location.
199201
// Note: override will fail if the resource path does not exist.
200202
// +required
203+
// +kubebuilder:validation:XValidation:rule="!(self == '/kind' || self == '/apiVersion')",message="Path cannot target typeMeta fields (kind, apiVersion)"
204+
// +kubebuilder:validation:XValidation:rule="!(self.startsWith('/metadata') && (!(self.startsWith('/metadata/annotations') || self.startsWith('/metadata/labels'))) || self == '/metadata')",message="Path can only target annotations and labels under metadata"
205+
// +kubebuilder:validation:XValidation:rule="!self.startsWith('/status')",message="Path cannot target status fields"
206+
// +kubebuilder:validation:XValidation:rule="self.startsWith('/')",message="Path must start with /"
201207
Path string `json:"path"`
202208
// Value defines the content to be applied on the target location.
203209
// Value should be empty when operator is `remove`.

apis/placement/v1alpha1/zz_generated.deepcopy.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apis/placement/v1beta1/zz_generated.deepcopy.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apis/v1alpha1/zz_generated.deepcopy.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/placement.kubernetes-fleet.io_clusterresourcebindings.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,8 +542,8 @@ spec:
542542
managed by Fleet (i.e., specified in the hub cluster manifest). This is the default
543543
option.
544544
545-
Note that this option would revert any ad-hoc changes made on the member cluster side in
546-
the managed fields; if you would like to make temporary edits on the member cluster side
545+
Note that this option would revert any ad-hoc changes made on the member cluster side in the
546+
managed fields; if you would like to make temporary edits on the member cluster side
547547
in the managed fields, switch to IfNotDrifted option. Note that changes in unmanaged
548548
fields will be left alone; if you use the FullDiff compare option, such changes will
549549
be reported as drifts.

config/crd/bases/placement.kubernetes-fleet.io_clusterresourceoverrides.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,19 @@ spec:
327327
Path defines the target location.
328328
Note: override will fail if the resource path does not exist.
329329
type: string
330+
x-kubernetes-validations:
331+
- message: Path cannot target typeMeta fields (kind,
332+
apiVersion)
333+
rule: '!(self == ''/kind'' || self == ''/apiVersion'')'
334+
- message: Path can only target annotations and labels
335+
under metadata
336+
rule: '!(self.startsWith(''/metadata'') && (!(self.startsWith(''/metadata/annotations'')
337+
|| self.startsWith(''/metadata/labels''))) ||
338+
self == ''/metadata'')'
339+
- message: Path cannot target status fields
340+
rule: '!self.startsWith(''/status'')'
341+
- message: Path must start with /
342+
rule: self.startsWith('/')
330343
value:
331344
description: |-
332345
Value defines the content to be applied on the target location.
@@ -352,6 +365,15 @@ spec:
352365
- Delete
353366
type: string
354367
type: object
368+
x-kubernetes-validations:
369+
- message: jsonPatchOverrides cannot be set when the override
370+
type is Delete.
371+
rule: '!(has(self.overrideType) && self.overrideType == ''Delete''
372+
&& self.jsonPatchOverrides.size() != 0)'
373+
- message: jsonPatchOverrides must be set when the override
374+
type is JSONPatch.
375+
rule: '!(has(self.overrideType) && self.overrideType == ''JSONPatch''
376+
&& self.jsonPatchOverrides.size() == 0)'
355377
maxItems: 20
356378
minItems: 1
357379
type: array

config/crd/bases/placement.kubernetes-fleet.io_clusterresourceoverridesnapshots.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,19 @@ spec:
341341
Path defines the target location.
342342
Note: override will fail if the resource path does not exist.
343343
type: string
344+
x-kubernetes-validations:
345+
- message: Path cannot target typeMeta fields
346+
(kind, apiVersion)
347+
rule: '!(self == ''/kind'' || self == ''/apiVersion'')'
348+
- message: Path can only target annotations and
349+
labels under metadata
350+
rule: '!(self.startsWith(''/metadata'') && (!(self.startsWith(''/metadata/annotations'')
351+
|| self.startsWith(''/metadata/labels'')))
352+
|| self == ''/metadata'')'
353+
- message: Path cannot target status fields
354+
rule: '!self.startsWith(''/status'')'
355+
- message: Path must start with /
356+
rule: self.startsWith('/')
344357
value:
345358
description: |-
346359
Value defines the content to be applied on the target location.
@@ -366,6 +379,15 @@ spec:
366379
- Delete
367380
type: string
368381
type: object
382+
x-kubernetes-validations:
383+
- message: jsonPatchOverrides cannot be set when the override
384+
type is Delete.
385+
rule: '!(has(self.overrideType) && self.overrideType ==
386+
''Delete'' && self.jsonPatchOverrides.size() != 0)'
387+
- message: jsonPatchOverrides must be set when the override
388+
type is JSONPatch.
389+
rule: '!(has(self.overrideType) && self.overrideType ==
390+
''JSONPatch'' && self.jsonPatchOverrides.size() == 0)'
369391
maxItems: 20
370392
minItems: 1
371393
type: array

config/crd/bases/placement.kubernetes-fleet.io_clusterresourceplacements.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,8 +1807,8 @@ spec:
18071807
managed by Fleet (i.e., specified in the hub cluster manifest). This is the default
18081808
option.
18091809
1810-
Note that this option would revert any ad-hoc changes made on the member cluster side in
1811-
the managed fields; if you would like to make temporary edits on the member cluster side
1810+
Note that this option would revert any ad-hoc changes made on the member cluster side in the
1811+
managed fields; if you would like to make temporary edits on the member cluster side
18121812
in the managed fields, switch to IfNotDrifted option. Note that changes in unmanaged
18131813
fields will be left alone; if you use the FullDiff compare option, such changes will
18141814
be reported as drifts.

0 commit comments

Comments
 (0)