-
Notifications
You must be signed in to change notification settings - Fork 572
Add CRDCompatibilityRequirement #2479
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?
Add CRDCompatibilityRequirement #2479
Conversation
Hello @mdbooth! Some important instructions when contributing to openshift/api: |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: 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 |
@mdbooth: The following test failed, say
Full PR test history. Your PR dashboard. 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. I understand the commands that are listed here. |
// ensure that only a target CRD compatible with compatibilityCRD may be admitted. | ||
// This field is required. | ||
// +kubebuilder:validation:MinLength=1 | ||
// +kubebuilder:validation:MaxLength=1000000 |
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 maximum request size supported is 1.5MiB, in the worst case, each rune will be exactly 1 byte, so the maximum length here should be
// +kubebuilder:validation:MaxLength=1000000 | |
// +kubebuilder:validation:MaxLength=1572864 |
// metadata is the standard object's metadata. | ||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata | ||
// +optional | ||
metav1.ObjectMeta `json:"metadata"` |
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.
metav1.ObjectMeta `json:"metadata"` | |
metav1.ObjectMeta `json:"metadata,omitzero"` |
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 linter didn't warn me about that one!
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 am not sure why, a bug to look into I guess 🤔
// +kubebuilder:validation:MaxLength:=253 | ||
// +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character." | ||
// +required | ||
CRDRef string `json:"crdRef,omitempty"` |
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 don't use Ref in openshift APIs. I would generally expect this to be more like a local object reference, so to be consistent with other APIs, WDYT of
crd:
name:
Potentially, instead of crd
, what about target
?
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.
Certainly ok on dropping ref
if that's the convention.
Are you channeling https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#object-references by any chance here?
It is okay to have the "{field}" component indicate the resource type. For example, "secretRef" when referencing a secret. However, this comes with the risk of the field being a misnomer in the case that the field is expanded to reference more than one type.
Could this ever reference a different type? It feels unlikely. That would likely require a different tool. With that in mind, I think crd
is more explicit and therefore more obvious. This object is about adding requirements to a CRD, and the CRD is specified in the crd
field.
Is there any circumstance when we might add additional information to a CRD reference? The only things I can think of are:
- UID - this precise CRD and not its successors
- APIVersion - CRD version v2beta1
So that's realistic, at least.
I'll change it to
crd:
name:
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 had leant on target for a few reasons, yes, it's more generic, but also I wondered if it might have been more intuitive and idiomatic, I have seen many targetRef
before across K8s APIs. We do talk about the field being a target in the godoc, so it felt like it made sense.
// +kubebuilder:validation:MinLength=1 | ||
// +kubebuilder:validation:MaxLength:=253 |
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.
Inconsistent use of :=
vs =
at the end here?
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 difference between the 2?
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 can't find :=
in the docs at all now I look for it. I'm assuming I've just cargo-culted this from somewhere and should stop.
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.
Kubebuilder supports both :=
and =
on all of its markers. Upstream markers (e.g. +default) do not support :=
, so we would prefer all markers use =
and we shouldn't use :=
.
Has lead to issues in the past where upstream markers have been ignored because of the :=
typo
// creatorDescription is a string describing the owner of this CRDCompatibilityRequirement. It will be printed in any error or | ||
// warning emitted by any of the CRDCompatibilityRequirement's webhooks. It should indicate to the recipient who they need to coordinate | ||
// with in order to safely update the target CRD. The message emitted will be: "This requirement was added by <creatorDescription>". | ||
// This field is required. | ||
// +kubebuilder:validation:MinLength=1 | ||
// +kubebuilder:validation:MaxLength=253 | ||
// +required | ||
CreatorDescription string `json:"creatorDescription,omitempty"` |
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.
Have you considered what a valid set of characters might look like for this field? Since this is being used as input to a logging output, I assume it would be bad if I tried to inject some json into this?
creatorDescription: "\" nastySomething:\"doBadThingToLogs\""
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'm assuming that any JSON logging library we're using escapes its output. If it doesn't we already have severe problems! We certainly don't want to ask the user to do their own escaping here.
It's a while since I wrote this, and I just re-read it with fresh eyes. I think it's usefully descriptive? I can't think how I would improve it.
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 was thinking along the lines of restricting the valid character set to [a-zA-Z0-9\ ]
to prevent folks from putting any data into this string that we need to be worried about or even consider the safety element of
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.
That just feels like a footgun. For example, it would prevent us from using non-US ASCII characters in a string which is intended to describe people. I don't think we can usefully validate this string, and I think we can trust logging software to escape any possible byte sequence correctly.
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.
Kubernetes is built on US ASCII already, all of our APIs, code and even user facing logging is also US ASCII. If we implement this validation, we can always relax it later if we were to get complaints. I'm open to a less restrictive set if you have a suggestion, but I don't think we should leave it unbounded
// +kubebuilder:validation:MinLength=1 | ||
// +kubebuilder:validation:MaxLength:=253 | ||
// +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character." |
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.
All validations like this must be explained in prose inside the godoc
// +kubebuilder:validation:MinLength=1 | |
// +kubebuilder:validation:MaxLength:=253 | |
// +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character." | |
// crdRef must be at most 253 characters in length and must consist only of lower-case alphanumeric characters, periods (.) and hyphens (-). Each period separated label must start and end with an alphanumeric character and be at most 63 characters in length. | |
// +kubebuilder:validation:MinLength=1 | |
// +kubebuilder:validation:MaxLength:=253 | |
// +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character." |
Please apply similar feedback to other fields
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.
Presumably we do this for UX, and in general I get it. However, in this case (and presumably many similar cases), I believe the additional text actually makes the UX worse because it's complex, distracting, and irrelevant. The 'correct' validation here is 'the name of a CRD'. This CRD may or may not exist yet, so we can't even validate it with a VAP. All we're trying to do here with this somewhat complex validation (which I presumably just copied from somewhere) is exclude a certain class of thing which is obviously wrong because it would fail k8s naming validation. If it excludes the valid name of a CRD, that would be a bug. If this ever did happen, the user would open a bug against the product because the field did not accept the name of their CRD, not because they mentally executed the pseudocode in the documentation1. Even if they did read the pseudocode, it might lead them to the incorrect belief that we only intend to support CRDs whose names conform to some arbitrary additional restrictions.
I can see that this kind of validation is useful when we're trying to guide the user to form correct input for something we're going to create, but here we're just referencing something which was validated elsewhere with rules we don't control. Our own validation is nothing more than a loose proxy to exclude a small class of obvious error.
Footnotes
-
Which in any case hasn't corresponded to the actual validation for the last 18 months since we tweaked it but forgot to make the corresponding change to the pseudocode in the docs, but nobody noticed because we don't run tests against the docs2. ↩
-
A linter which uses AI to attempt to validate that godoc remains consistent with the code it describes 🤔 ↩
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.
Validation markers are not documented in any user readable documentation by default. We document all validations in the text to explain what the valid values are, so that folks using oc explain
or reading our generated API documentation in the product docs have a sense of what value input is.
While I get your point about us documenting a validation that isn't actually ours, we aim to be consistent in validating the field validations across all fields in our APIs, independent of whether its our own restriction, or something imposed upon us
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.
Ack. I'll also make it clear that it's a proxy validation, just in 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.
The validation of a CRD name is never going to change, I don't think we need to document that this is proxy validation
// CRDCompatibilityRequirementStatus defines the observed status of the CRD Compatibility Requirement. | ||
// +kubebuilder:validation:MinProperties=1 | ||
type CRDCompatibilityRequirementStatus struct { | ||
// conditions is a list of conditions and their status. |
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.
Document valid condition types?
// +optional | ||
// +listType=map | ||
// +listMapKey=type | ||
// +kubebuilder:validation:MaxItems=16 |
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.
Please add a MinItems 1 as well
// uid is the uid of the observed CRD. | ||
// +kubebuilder:validation:MaxLength=36 | ||
// +kubebuilder:validation:MinLength=1 | ||
// +kubebuilder:validation:Format=uuid |
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.
IIRC, the API server won't actually validate this at admission time, so we should validate this ourselves with a CEL rule (please 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.
I'm convinced I've written an API validation for this before, but I can't find it now 🤔
Is there a canned one you're aware of that's already battle hardened? It's not actually important, so if this requires anything more than a trivial amount of work I'll just remove the validation.
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.
Thinking about it further: this is status. A validation failure here is only ever likely to result in a bug. I'm just going to remove it because it's unnecessary tight coupling.
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.
Even though this is status, it should be validated correctly
// +kubebuilder:validation:Format=uuid
// +kubebuilder:validation:XValidation:rule="!format.uuid().validate(self).hasValue()",message="uid must be a valid UUID. It must consist only of lower-case hexadecimal digits, in 5 hyphenated blocks, where the blocks are of length 8-4-4-4-12 respectively."
// metadata is the standard list's metadata. | ||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata | ||
// +optional | ||
metav1.ListMeta `json:"metadata"` |
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.
metav1.ListMeta `json:"metadata"` | |
metav1.ListMeta `json:"metadata,omitzero"` |
/assign @damdo |
No description provided.