-
Notifications
You must be signed in to change notification settings - Fork 1.5k
KEP-5073: Declarative Validation: Explain and update document with cross-field validation information #5290
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: master
Are you sure you want to change the base?
KEP-5073: Declarative Validation: Explain and update document with cross-field validation information #5290
Conversation
b8205b9
to
63eae72
Compare
…oss-field validation information
63eae72
to
a65ce7c
Compare
/assign @deads2k @jpbetz @thockin |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: aaron-prindle 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 |
#### Cross-Field Validation and Ratcheting | ||
For cross-field validations, the validation logic is evaluated at the common ancestor of the fields involved. This approach is necessary for supporting ratcheting. While validation tags (eg: +k8s:maximum=siblingField, +k8s:unionMember , etc.) may be placed on an individual field for clarity, the tag and its associated validation logic will be "hoisted" to the parent struct during code generation. This "hoisting" means the validation is treated as if it were defined on the common ancestor. By anchoring the cross-field alidation logic at the common ancestor, regardless of tag placement, the ratcheting design can more reliably determine how to perform equality checks across the relevant type nodes and decide if re-validation is necessary. | ||
|
||
As noted in the Ratcheting section there is an additional challenge that arises if a cross-field validation rule (e.g. X < Y) is defined on a common ancestor struct/field, and an unrelated field (e.g. Z) within that same ancestor is modified. This change to Z makes the common ancestor “changed” overall, triggering re-validation of the X < Y rule. If this rule was recently evolved, it might now fail even if X and Y themselves are not modified by the user’s update. This could violate the principle “Unchanged fields do not cause update rejections”. In practice this means that the validation rules (or validation-gen generally) might have to be more explicit where each validation rule explains “I only care about these fields for ratcheting”. | ||
|
||
For the initial implementation, this behavior will be documented, and cross-field validation rules must handle ratcheting themselves. This means that in the initial implementation of the cross-field dedicated tags referenced in the document (+k8s:unionMember, etc.), they will handle ratcheting of the fields they operate on directly. See the Ratcheting section for more information on this issue as well as longer term plans on addressing this challenge. |
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.
Do you think it is more nature that first paragraph is in cross-field section and the 2nd & 3rd paragraphs are in ratcheting section? Maybe you don't need to put a sub-title for that 1st paragraph and then refer to the ratcheting section of how to handle this challenge case?
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.
+1, I've combined paragraphs 2 & 3 into a single paragraph and de-duped the majority of text from the Ratcheting and Cross-Field Validation
section in #5292. This paragraph now explains:
- cross-field tags "hoist" all cross-field tags to the parent struct
- cross-field tags implement ratcheting for the fields they operate on
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.
nit only, looks good!
keps/sig-api-machinery/5073-declarative-validation-with-validation-gen/README.md
Outdated
Show resolved
Hide resolved
keps/sig-api-machinery/5073-declarative-validation-with-validation-gen/README.md
Outdated
Show resolved
Hide resolved
…tion-gen/README.md Co-authored-by: Joe Betz <[email protected]>
…tion-gen/README.md Co-authored-by: Joe Betz <[email protected]>
e67cef8
to
8d62579
Compare
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.
I wasn't expecting to see CEL in the table. I agree with the rest, though particulars around usage of the tags will need to be worked out. Do you want to do it here, on a followup KEP update, on the implementation PR, or somewhere else?
keps/sig-api-machinery/5073-declarative-validation-with-validation-gen/README.md
Outdated
Show resolved
Hide resolved
</td> | ||
<td> | ||
`x-kubernetes-validations` | ||
x-kubernetes-validations (CEL: !has(oldSelf...) || 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.
Accidentally left CEL here? If we're trying to avoid it, we don't need it here right?
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.
This intention of the text there was to show the OpenAPI equivalent for +k8s:immutable which would be using x-kubernetes-validations with a CEL expression similar to that shown. I have kept the text for now but am happy to remove this text. Just wanted to note the current intent which is aligned with previous discussion around CEL in v1.34. This column is to note how some declarative validation rules map-to/could-be-output as OpenAPI rules.
// +k8s:subfield({"type":"Denied", "status": "true"})=+k8s:unionMember | ||
|
||
// +k8s:subfield({"type":"Failed"})=+k8s:optional | ||
// +k8s:subfield({"type":"Failed"})=+k8s:immutable |
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.
The impl PR will go into the "immutable after create" versus "immutable once set"?
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.
Yes, the related impl KEP Update will go into the "immutable after create" versus "immutable once set".
```go | ||
type CertificateSigningRequestStatus struct { | ||
// +k8s:subfield({"type":"Approved"})=+k8s:optional | ||
// +k8s:subfield({"type":"Approved", "status": "true"})=+k8s:unionMember |
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.
I thought I remembered that unions were named in one of the previews I saw. The detail will be in the impl PR?
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.
I have updated this to use named unions now (the +k8s:unionMember{"union": "unionName"}).
For simple cases where there is only one union on a struct, currently there is a default name when no union
name value is set (example from dev-branch: https://github.com/jpbetz/validation-gen/blob/main/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/union/undiscriminated/simple/doc.go#L33)
oh, and a note that breaking on sentences makes it easier to comment on the right lines. |
f63f0af
to
40bfe3a
Compare
Noted, I've updated the KEP Update changes here to break on sentences now. |
One-line PR description: This addresses how we intend to handle cross-field validations with Declarative Validation.
Issue link: Declarative Validation Of Kubernetes Native Types With validation-gen #5073