-
Notifications
You must be signed in to change notification settings - Fork 440
✨ Change CRD generation logic to honor k8s:immutable #1216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: lalitc375 The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Welcome @lalitc375! |
Hi @lalitc375. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
func (Immutable) ApplyToSchema(schema *apiext.JSONSchemaProps) error { | ||
schema.XValidations = append(schema.XValidations, apiext.ValidationRule{ | ||
Message: "Value is immutable", | ||
Rule: "self == oldSelf", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this error out in the create case as oldSelf
will be undefined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It won't, there is always a "oldSelf" since the rule is attached to the field and only takes effect when the field exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since the rule is attached to the field and only takes effect when the field exists.
Not quite true, but it's still safe.
Rules that include oldSelf
are known as transition rules, and the CEL implementation detects that a rule is a transition rule.
It will only run a transition rule when it has a value for both self
and oldSelf
. So only on updates, not when the field first appears.
But, you could have a rule without oldSelf
, in which case, the rule would run even when the field first appears.
There's also optionalOldSelf
which allows transition rules to run when there is no value for oldSelf
, but you have to handle those differently.
Which brings me to... The semantic here is that I could have an object with a field we say is immutable. What does it actually mean to be immutable?
There are two interpretations IMO:
- Once a value has been set for X, it cannot be changed (omitted -> set is allowed on updated)
- Value for X can only be set on create (omitted counts as a value)
This implements the first of those, how does it work in the declarative validation project?
If it is the latter, we would need an optionalOldSelf
rule and implement a different validation rule
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @JoelSpeed for providing insights on CEL rules.
+k8s:immutable in Declarative validation project can allow setting empty value to non-empty value during update, but it doesn't allow changing value from one non-empty to another non-empty. So, it is the following interpretation.
Once a value has been set for X, it cannot be changed (omitted -> set is allowed on updated)
It doesn't allow setting non-empty to empty in update. Which the current cel expression will allow. I will see how this can be achieved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way for us to have tests that actually test the contents of the CEL rule? This seems pretty easy to get wrong and once we've released something like this, fixing it up will be extremely difficult/impossible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could set up an envtest style integration suite and create a series of Create/Update calls to test the validations. That would be my preferred route for testing these at least
Which the current cel expression will allow. I will see how this can be achieved.
The only way I've found to do this is to make sure that the nearest required parent has a rule that says if the field exists, it cannot be removed. But there may be something smarter we can do
/ok-to-test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/cc @aaron-prindle
PTAL if this align with stand alone +k8s:immutable tag in latest design.
func (Immutable) ApplyToSchema(schema *apiext.JSONSchemaProps) error { | ||
schema.XValidations = append(schema.XValidations, apiext.ValidationRule{ | ||
Message: "Value is immutable", | ||
Rule: "self == oldSelf", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It won't, there is always a "oldSelf" since the rule is attached to the field and only takes effect when the field exists.
@yongruilin: GitHub didn't allow me to request PR reviews from the following users: aaron-prindle. Note that only kubernetes-sigs members and repo collaborators can review this PR, and authors cannot review their own PRs. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
cc @JoelSpeed |
/hold |
From the KEP Update: Related WIP dev-branch PR here: jpbetz/validation-gen#103 The semantics for +k8s:immutable are:
The semantics for +k8s:frozen are:
|
+1 Would something along the lines of EDIT: Modified CEL proposal to account for the fact that our conversion from Go to CEL types already accounts for omitempty. |
@@ -325,6 +328,19 @@ type XIntOrString struct{} | |||
// to be used only as a last resort. | |||
type Schemaless struct{} | |||
|
|||
// +controllertools:marker:generateHelp:category="CRD validation" | |||
// Immutable marks a field as immutable. | |||
// The value of an immutable field may not be changed after creation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's expand the semantics here to clarify what exact transitions are allowed.
Let's use the term "set" instead of "creation" here since immutable fields can set after initial resource creation.
This change adds logic to understand and interpret k8s:immutable tag in controller-gen. This tag is getting introduced for native types in K8s as part of 5073-declarative-validation-with-validation-gen KEP.
On detecting the tag, A CEL validation is added for the corresponding field.