-
Notifications
You must be signed in to change notification settings - Fork 5.2k
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
Update alpha field guidance #869
Conversation
cc @deads2k @lavalamp @smarterclayton @bgrant0607 as those involved in the api-machinery meetings around this @kubernetes/sig-api-machinery-pr-reviews @kubernetes/sig-api-machinery-proposals @kubernetes/api-reviewers |
4bcfc7c
to
71f4e76
Compare
contributors/devel/api_changes.md
Outdated
} | ||
``` | ||
|
||
3. In validation, ensure that the new field is rejected if the feature gate is disabled: |
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.
Doing this would make turning on the feature-gate a one way operation since future updates (even updates that attempt to delete the thing from GC) would fail.
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.
gates are for alphas, and we have no strong guarantees for alpha anyway?
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.
gates are for alphas, and we have no strong guarantees for alpha anyway?
If you had an alpha field on a Deployment, then you wanted to turn it off, after you turned it off, you would not be able to touch the deployment again and might not even be able to update status on the objects. In fact, because of the way validation and GC works, you may not even be able to delete the object after turning on the alpha field.
The only "fix" is to rewrite the objects and hope no one races you in. This becomes really problematic for alpha fields that have reflections in status which are controller maintained. In such a case, I don't see how you turn alpha back off with this validation requirement.
I'm not saying we can't do it, but the warnings around this need to be explicit. I doubt that its an obvious repercussion of the approach for many/most people.
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.
There is a similar issue with enabling an alpha version... a cluster admin has to be aware that they might have to delete all alpha data before upgrading or they can get stuck with undecodeable content in etcd (if the alpha version was removed in the upgraded version, which is allowed).
I'll update the text to be explicit, but enabling an alpha version or an alpha feature puts more burdens on a cluster admin, and I'm ok with that.
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.
Rejection when specifying an unknown field is incompatible with expected behavior.
Strong schema validation needs to be optional, and I don't see a reason to treat disabled alpha fields differently. Discussed further here:
kubernetes/kubernetes#5889
More consistent behavior would be to ensure that the contents were dropped when the field is disabled.
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.
Rejection when specifying an unknown field is incompatible with expected behavior.
More consistent behavior would be to ensure that the contents were dropped when the field is disabled.
good point, will update, though I'll have to think about where we'd recommend the clearing be done, especially for fields in reused types (like PodSpec). There's not a great single place to clear the field based on a feature gate:
- PrepareForCreate/PrepareForUpdate would have to be set in every resthandler that uses the type, and it'd be tough to ensure we didn't miss any
- Validation functions shouldn't mutate
- defaulting or conversion would affect components other than the API server
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.
More consistent behavior would be to ensure that the contents were dropped when the field is disabled.
There are three types of alpha fields:
- new additive fields an old server would ignore while still accepting the rest of the object.
- new fields in a union type (e.g. local persistent volume source) that would cause an old server to reject the object (since it did not have a recognized field in the union type)
- new values for an enumerated field an old server would reject.
I think only the first type should be dropped. The other two should fail 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.
Opened kubernetes/kubernetes#50924 for the existing feature-gated alpha fields we have to drop contents of disabled alpha fields on create/update
} | ||
``` | ||
|
||
The latter requires that all objects in the same API group as `Frobber` to be | ||
replicated in the new version, `v6alpha2`. This also requires user to use a new | ||
replicated in the new version, `v7alpha1`. This also requires user to use a new |
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 think this particular example offers a strong amount of guidance.
before it seemed to suggest taking an api 'back to alpha', chronologically, like so:
v6alpha1
v6beta1
v6
v6alpha2
and now what makes more sense to me to suggest a main version bump, again chronologically
v6alpha1
v6beta1
v6
v7alpha1
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.
agree, starting v6alpha2 after v6 exists wouldn't make sense.
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 was recently pointed out to me that we don't really document this API versioning convention anywhere.
metadata: | ||
name: myfrobber | ||
annotations: | ||
frobbing.alpha.kubernetes.io/width: 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.
Is this annotation process no longer advocated? @cmluciano !!
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 is not advocated. see the links in this PR's description for the problems. the alternatives to the approach described in this PR are:
- use annotations
- exposes you to time-bomb data added while running an earlier version of the server
- no way for an admin to control use
- if the field graduates to beta/stable it requires breaking clusters using alpha fields or trying to migrate/surface the options in both an annotation and field at the same time (which doesn't work)
- use fields with "alpha" in the name
- if the field graduates to beta/stable it requires breaking clusters using alpha fields or trying to migrate/surface the options in two fields at the same time (which doesn't work)
- use fields without "alpha" in the name and allow changing them in incompatible ways
- breaks old servers and/or clients if the schema changes on the way to beta/stable
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 think we need to mention the old approach (and that it is no longer recommended/allowed for new features), since it will still exist in a number of places for some time to come.
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 use of this feature gate process I can look at?
it was used for the priority fields added to the pod spec in kubernetes/kubernetes@91f893e |
// param ... | ||
Param string `json:"param" protobuf:"bytes,2,opt,name=param"` | ||
// width ... | ||
Width *int32 `json:"width,omitempty" protobuf:"varint,3,opt,name=width"` |
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 prescribe adding the new field to the end of the Go struct, with the intention of allowing existing "unkeyed" composite literals to remain valid when recompiled, or do you mandate use keyed elements so that existing code can't impose assumptions about field order?
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 prescribe adding the new field to the end of the Go struct, with the intention of allowing existing "unkeyed" composite literals to remain valid when recompiled
No, unkeyed literal compatibility is impossible when adding new fields.
Adding new fields at the end just makes it easier to see the incrementing protobuf tag.
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.
Ah, yes, a trip to the Go Playground confirmed what I had forgotten. I was thinking that that an unkeyed composite literal could get away with specifying a prefix of the fields, but then this is where that trick of using a field called "_" comes in, defending against callers using unkeyed literals.
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.
If this is the new guidance ( I thought we had larger concerns with this approach when we discussed it last year) we need to spread the word FAR and WIDE.
Are we comfortable with the idea that an alpha feature can burn a field name basically forever? Do we need alpha fields to be named specially? Beta seems like a safer bet...
contributors/devel/api_changes.md
Outdated
2. Add the field to the API type: | ||
|
||
* mark the field `omitempty` and optional | ||
* ensure the field is entirely absent from the API when empty (might require making the field a pointer) |
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 optionals should be pointers or otherwise nil-able
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.
Link to the documentation on optional fields:
contributors/devel/api_changes.md
Outdated
} | ||
``` | ||
|
||
3. In validation, ensure that the new field is rejected if the feature gate is disabled: |
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.
gates are for alphas, and we have no strong guarantees for alpha anyway?
Agree. This is the start. The alternatives (annotations, field with alpha-name, field without alpha-name that allows changing the schema) all have major downsides. To be clear, this PR is an attempt to summarize the outcomes of the linked discussions for general consumption. Please correct my understanding if I'm misrepresenting those in any way.
I don't think we have much of an option... if you name the field specially, there is no good path to beta/stable that doesn't summarily break everyone using the alpha field. If you don't name it specially, and just change the schema, you break decoding of new beta data by old clients and servers with inert alpha fields in their internal structs. |
gates ensure the server doesn't accept alpha data without opt-in, since it can drive unwanted or unstable behavior |
In future versions: | ||
|
||
* if the feature progresses to beta or stable status, the feature gate can simply be enabled by default. | ||
* if the schema of the alpha field must change in an incompatible way, a new field name must be used. |
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.
so, if we're working with a new alpha field Quuxer
, and, while still in alpha, we want to change the value type from int
to resource.Quantity
, we have to abandon the name Quuxer
forever? That seems to partially defeat the purpose of alpha...
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.
to be clear, this is talking about changing an alpha field that has already been included in a release.
until we generate servers and clients with alpha fields completely absent from the go structs, changing the schema breaks old clients and servers:
- an old client with the inert alpha field
quxxer int
in its go struct would fail to decode a server sending data including the beta field"quxxer":"1m"
, which breaks forward client compatibility - an old server with the inert alpha field
quxxer int
in its go struct would fail to decode a client sending data including the beta field"quxxer":"1m"
, which breaks backward client compatibility
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 is admittedly a compromise, but the alternative discussed was to always prefix alpha fields with alpha
, which would always incur breakage when transitioning out of alpha, as it is not possible to support multiple representations of the same attribute in the same API version.
Also ref kubernetes/kubernetes#4855 |
contributors/devel/api_changes.md
Outdated
|
||
The preferred approach adds an alpha field to the existing object, and ensures it is disabled by default. | ||
|
||
1. Add a feature gate to the API server to control enablement of the new field (and associated function): |
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.
A link to the file or at least a string to search for would be useful.
contributors/devel/api_changes.md
Outdated
// param ... | ||
Param string `json:"param" protobuf:"bytes,2,opt,name=param"` | ||
// width indicates how wide the object is. | ||
// This field is alpha-level and should only be sent to servers that enable the Frobber2D feature. |
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.
@mbohlool Would it be possible for us to strip disabled fields out of the OpenAPI spec?
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 we want to remove them if the Frobber2D feature is disabled? ... (updating comment, removing the old one)
Yes, we need to pass DefaultFeatureGate
(probably converting it to simple map[string]bool
) to the generator and add a comment tag here for alpha fields (e.g. // +openapi-gen: EnableOn(Forbber2D)
or // +openapi-gen: AlphaField(Forbber2D)
). Should I create an issue for it?
Removing fields from OpenAPI spec would have a nice effect on kubectl validation when it uses OpenAPI spec for validation.
Also relevant: |
Thanks, @liggitt. I think the only major issue is what to do when a value is specified for a disabled field. IMO, we need to drop the contents, silently by default, as with entirely unrecognized fields. |
Updated with links to other docs, updated guidance to clear disabled alpha fields before storing |
Thanks. |
Automatic merge from submit-queue |
Automatic merge from submit-queue (batch tested with PRs 51682, 51546, 51369, 50924, 51827) Clear values for disabled alpha fields Fixes kubernetes#51831 Before persisting new or updated resources, alpha fields that are disabled by feature gate must be removed from the incoming objects. This adds a helper for clearing these values for pod specs and calls it from the strategies of all in-tree resources containing pod specs. Addresses kubernetes/community#869
Summarizing outcome of discussions with @kubernetes/sig-api-machinery-misc
ref: