-
Notifications
You must be signed in to change notification settings - Fork 452
⚠️ Start from local type declaration when applying schema #1270
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
⚠️ Start from local type declaration when applying schema #1270
Conversation
/approve cancel As above, needs discussion before we merge this |
I believe you'll need to adjust the min & max markers to follow refs - and other markers that assert json schema types eg. controller-tools/pkg/crd/markers/validation.go Lines 394 to 400 in 257e3a0
|
@JoelSpeed
it was simply not possible to have these markers on the field (#1269). So for this case this wouldn't be a breaking change. I assume there are other cases where it was possible to define the markers and now the behavior changes? P.S. Just a single data point. I ran this against Cluster API and there it leads to no changes |
If I were to create a type alias as
And then use that in a field
It would generate the schema validation
And then with this PR, instead would generate
The effect on this example is that the validation actually remains the same. To satisfy the If however, you set the field
Now I can set this field to anything in the range With this PR, it would then become
And now the valid range is Now you could argue that this was always the intention, but it may have been a mistake from folks that they never picked up, and this change would reveal it |
To avoid sprawling ref following across all the markers (and forgetting to do this in the future for new markers), I've effectively flattened the refs in this PR before the markers are applied |
I would be fine with this change |
Is it possible to detect this situation from the generator (with reasonable effort)? |
Potentially? We could update the markers to emit a warning if they overwrite an existing value? Though I think that's actually a desired use case? Think about the port example where we know a port number must be in the range I wouldn't want to prevent the use case where someone locally loosens the validation at the field level |
To my knowledge we don't have the prior state so we can't compare A/B before and after to see if the PR is breaking someone |
Q: If this leads to "effective" changes for someone, they are able to "fix" that situation for them by adjusting their "local" markers on the fields accordingly, right? |
This is the exactly gateway APIs use case. In general I'd expect default validation to be tighter and then potentially loosened at different uses of a type. |
Yes. All they need to do is adjust the markers at the field level. Field level will now always be the source of truth if the marker is defined on both, for things like Min/Max{Length,Items,Properties}. In theory this makes the project more flexible, not less |
I don't fully understand the code change here, but agree to all comments and examples above. Most/all projects using controller-gen have generated files under source control. Some might hide the diff for generated CRDs in PRs, but hopefully have tests to catch any regression. I am 👍 for this change. |
Is there any chance of getting this fix into a patch release of controller-tools, or would we have to wait for the next major release? I am really eager to upgrade to K8s 1.34 in cert-manager, as we also have downstream projects currently blocked by this. I opened up kubernetes-sigs/gateway-api#4049 as a workaround (thanks, Joel), and I also have another potential workaround available. But I was hoping to avoid working around this issue. |
I don't know if we even have consensus to merge this PR (I'm in favor though) In general it's also possible to use controller-gen from the main branch |
AFAICT, Kubernetes considers I have this type alias that I tried to use later with tighter field validations: // ---
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`
type DNS1123Label = string
type Example struct {
// ---
// We prepend "example-" to avoid collisions with other [corev1.PodSpec.Volumes],
// so the maximum is 8 less than the inherited 63.
// +kubebuilder:validation:MaxLength=55
// +required
Name DNS1123Label `json:"name"`
} Touching that
crd-schema-checker estimates similarly:
Removing the field-level MaxLength changes the schema to
|
Sounds like a bug, can you please report this to k/k? |
Agreed, sounds like a bug in K/K, but also, this PR would fix the generated schema for you |
I'll try to make a minimal reproduction. 🤞🏻 I hope not to get a "don't do that" when I show a schema with two maxLength on one field. |
Regarding this PR, I suspect that there is no approach to combining markers that can express every OpenAPI schema. I like the simplicity of fields "overriding" types. 🤔 I'm struggling to imagine a case where Edit: Rather, every way I imagine using |
📝 Consider a type with type: integer
allOf:
# smallest value is one
- minimum: 0
exclusiveMinimum: true
# smallest value is one
- minimum: 1 |
@alvaroaleman Any strong opinion on whether this should or shouldn't move forward? @sbueringer (#1270 (comment)) and I are both ok with moving it forward I believe |
No strong opinion either way |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: sbueringer The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
LGTM label has been added. Git tree hash: 2e74693c106978b1c41c5737dcd17ce3b3dba4c6
|
I would recommend using controller-gen from a main branch commit |
A number of our markers require information about the type before they can be applied, for example,
+kubebuilder:validation:Minimum
requires the type of the scheme to be an integer or number.However, if I'm using a local type declaration
And I then use this in a field
Currently, this doesn't work.
The reason for this is that while we fetch the type schema, we return a link to the schema, and then try to apply the markers for the field.
Because we only have a link to the schema, the
type
of the schema is empty, and the markers fail to apply.This change effectively moves some of the flattening logic earlier in the process, so that rather than returning a link to the type schema to be flattened later, we return the actual type schema with its markers already applied.
This allows the field level markers to override (breaking change!) what was on the schema for the type, where previously it would create an
allOf
validation, meaning there was no way to override locally, meaning local field level markers could only tighten, not loosen validation of an existing types markers. Since the local field markers could only tighten validation, this shouldn't actually be a breaking change for the APIs that have done this in the past, but their schemas will change and now only represent the tighter validation.This could be an issue however if folks have previously tried to override locally (loosening) and not realised that their local field level markers were pointless, the schema will change to loosen the validation with this change in place.
/hold Since this could be breaking, this needs some discussion between maintainers and the community
CC @sbueringer @erikgb @alvaroaleman
Fixes #1269