Skip to content
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

Field-level versioning #34508

Open
lavalamp opened this issue Oct 10, 2016 · 85 comments
Open

Field-level versioning #34508

lavalamp opened this issue Oct 10, 2016 · 85 comments
Labels
kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. kind/feature Categorizes issue or PR as related to a new feature. lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness. priority/important-soon Must be staffed and worked on either currently, or very soon, ideally in time for the next release. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/architecture Categorizes an issue or PR as relevant to SIG Architecture.

Comments

@lavalamp
Copy link
Member

We have difficulties around moving fields through alpha, beta, GA. #30819 is one idea. I was talking with Brian earlier today and here is a sketch of something that we could do to solve the general problem.

We begin following semver for our api versions, adding a "patch" version. We define a new tag which can be added in a comment before a field, like this:

// +version:alpha=v1.5.3

When the field goes to beta (assuming it doesn't change):

// +version:alpha=v1.5.3,beta=v1.5.89

And at GA the field goes like this:

// +version:alpha=v1.5.3,beta=v1.5.89,stable=v1.5.183

If at any point in time the field is deleted (or moved and we don't want to autoconvert), and clients referencing the field might still exist, we can say:

// +version:alpha=v1.5.3,deleted=v1.5.8

The conversion machinery would enforce that any given version number is only used once (we can store the next version in a file somewhere for human convenience). This complete version should be tracked per-apiserver. (So federation-apiserver would likely have a different patch version.)

We'd use the same idea behind @smarterclayton's #33900 to allow clients to specify which minor version of the api they're intending to use, via Accept: headers.

Conversion routines, validators, swagger generation etc all need to be made to accept a full api version from clients and they can use the hints on the fields to tell whether the client knows about the field or not. Swagger can report whether fields are alpha or beta.

Likewise we can use the alpha/beta distinction to give admins the ability to disallow alpha or only allow stable fields to be used. (We can construct versions like v1.5.35-stable for this purpose)

@lavalamp lavalamp added kind/design Categorizes issue or PR as related to design. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. labels Oct 10, 2016
@lavalamp
Copy link
Member Author

Some people who might be interested in this: @bgrant0607 @smarterclayton @mbohlool @thockin

@bgrant0607
Copy link
Member

Ref #4855, #30819

@bgrant0607
Copy link
Member

@lavalamp I assume this approach would not allow the same field name to be used at different stages with different types.

I was thinking we'd use the tags to specify finer-grain versions, either API minor/patch versions or releases.

@thockin
Copy link
Member

thockin commented Oct 11, 2016

I don't understand this proposal. What do those versions mean? What
literally happens because of them? How do we overlap alpha/beta and
beta/ga ?

On Mon, Oct 10, 2016 at 7:44 PM, Brian Grant notifications@github.com
wrote:

@lavalamp https://github.com/lavalamp I assume this approach would not
allow the same field name to be used at different stages with different
types.

I was thinking we'd use the tags to specify finer-grain versions, either
API minor/patch versions or releases.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#34508 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AFVgVGZIp3Z7BWhii1g77PlgXF7J_bUYks5qyvgRgaJpZM4KTGnt
.

@bgrant0607
Copy link
Member

bgrant0607 commented Oct 11, 2016

@thockin I asked @lavalamp to keep it short. I'll write up more tomorrow.

Imagine we had actual distinct API versions containing the alpha, beta, and GA fields corresponding to some feature. They could all use the same internal rep, clients could request the API version containing the version of the field they understood, and users could use kubectl convert to upgrade their manifests.

Now assuming we don't really want to do that, how could we accomplish the equivalent in a single types.go file?

Ignoring whether we use comments or tags or something else to specify information on the fields, we'd put the fields in the same versioned types.go:

        AlphaFeature *bool `json:"alphaFeature,omitempty"`
        BetaFeature *bool `json:"betaFeature,omitempty"`
        Feature *bool `json:"feature,omitempty"`

Only the most mature version of the field would be serialized in etcd and only one of these fields would be visible to any client at a time.

@lavalamp proposed we use the proposal from #33900 to enable the client to request the desired field version. Another possibility is that we use the existing API version mechanism, using the apiVersion field and path.

With multiple different fields as above, rather than @lavalamp's syntax for specifying the level of maturity, I'd just specify the maturity level (alpha/beta/GA) of the field (e.g., so we could disable all alpha fields by default) and the range of "versions" that it was at that level of maturity.

If we used an extension of the existing API version mechanism, I'd add minor version, such as v1beta1.1 for the version following what's currently v1beta1, or v1.0.0-beta.1.1 if we want to go with actual semver. If we used headers as in #33900, we could use releases, such as 1.5.0-alpha.3. Either way, in the comment or tag, we'd specify a range of versions, such as 1.4.0-alpha.3..1.5.0-alpha.7.

@bgrant0607
Copy link
Member

Note that relying on a new mechanism, such as #33900, won't work for any existing clients.

@bgrant0607
Copy link
Member

One disadvantage of using release versions is that some projects that embed K8s (e.g., Openshift) have their own release numbers.

Anyway, I'm inclined to use a single versioning scheme for the API.

@lavalamp
Copy link
Member Author

It wasn't clear from my initial post, but these were intended to be api versions, not release versions. The patch version will rapidly diverge from the release patch version. We could make this more obvious, by prefixing with something other than "v". We could also not use semver and just have a clock that counts up with each api change--I didn't recommend that because we probably should produce semvers at some point, and it is easiest if we just keep them in that format to begin with.

@lavalamp
Copy link
Member Author

I assume this approach would not allow the same field name to be used at different stages with different types.

Right, you have to actually make a separate "real" api version for that. (Arguably this is a feature.)

@lavalamp
Copy link
Member Author

rather than @lavalamp's syntax for specifying the level of maturity, I'd just specify the maturity level (alpha/beta/GA) of the field (e.g., so we could disable all alpha fields by default) and the range of "versions" that it was at that level of maturity.

My suggestion is a superset of this. I was thinking you need to know what semantics the client is expecting to get, that it doesn't matter if the server has moved on. I'll have to think about it more, but I still think it is better to track the history and not just the current status.

@lavalamp
Copy link
Member Author

1.4.0-alpha.3..1.5.0-alpha.7

You can specify multiple versions in Accept headers. I'm not sure a range really gets you any benefit over that, unless you want to specify it separately and have it apply to all the things in the Accept header. (to avoid combinatorial explosion)

@lavalamp
Copy link
Member Author

What do those versions mean?

These provide an API history, and if a client gives a range or a version, we'd know:

  • which fields are new to that client
  • which fields the client will think are alpha/beta/ga.
  • which fields the client thinks exist which actually don't anymore.

The most recent alpha/beta/stable/marker determines the current state of the field. We can then stuff e.g. alpha fields into the list of alpha features automatically and allow them to be toggled on and off.

What literally happens because of them?

Swagger:

  • Check global alpha flag before adding alpha fields to the spec.
  • Produce schemas from the perspective of the client, i.e., previous points in time.

Conversion:

  • We could e.g. track an "unset" bit for fields when we know the client doesn't understand them, which are useful in update. Additionally we could just not deliver fields to clients if we know the client won't understand them.

Update:

  • Values for fields the client wasn't aware of can be automatically ignored in update requests.

Validation:

  • If validation rules change, we can validate as of the version the client knew of (and automatically fix items that would now be invalid, if possible)

Defaulting:

  • I think no changes necessary.

How do we overlap alpha/beta and beta/ga ?

This proposal doesn't overlap them from the perspective of the server. Each field is one of alpha, beta, or stable in any given fully specified version number.

@bgrant0607
Copy link
Member

@lavalamp I think we need a mechanism that does permit the representation to change. Otherwise we really are introducing hoops for no good reason.

The reason for ranges was to support multiple fields for the same feature, which is needed in order to support representation changes. The specification of maturity of the field similarly assumed there would be multiple fields, so it would capture history, not just current status.

I know you weren't proposing we use release versions, but was just pointing out that alternative.

I agree on semver.

@lavalamp
Copy link
Member Author

I suppose differing representations could be handled by allowing fields
with different go names to have the same json tag, and then generating json
parsers that are aware of this (would be a good reason to tear out ugorji).
However I don't think that makes any sense for the proto
representation--any given field number in the proto messages can't change
representation.

On Tue, Oct 11, 2016 at 2:08 PM, Brian Grant notifications@github.com
wrote:

@lavalamp https://github.com/lavalamp I think we need a mechanism that
does permit the representation to change. Otherwise we really are
introducing hoops for no good reason.

The reason for ranges was to support multiple fields for the same feature,
which is needed in order to support representation changes. The
specification of maturity of the field similarly assumed there would be
multiple fields, so it would capture history, not just current status.

I know you weren't proposing we use release versions, but was just
pointing out that alternative.

I agree on semver.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#34508 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAngllUSciBNwARfrXSypduKaGCSgZe8ks5qy_rhgaJpZM4KTGnt
.

@smarterclayton
Copy link
Contributor

I think having json names that reflect the particular state and
representation of a field is a feature. The only problem we have is
supporting multiple representations, which is really a problem when
you have three levels rather than two.

If we are backwards compatible in major versions, why not simply
collapse this into two states.

  1. Alpha (no back compat)
  2. Beta (back compat, no breaks)

All users eventually have to change beta to GA, which is not a magic
change (eventually deployments hits v1 and we drop v1beta1).

For existing GA objects, why have beta fields at all? Why not say
that beta = GA API but possibly not GA behavior? I don't really like
having "maybe backwards compatibility" - why not just have alpha until
we are ready to finalize API and then if we get it wrong make it ugly
in that API version and fix it in the next? We're trying really hard
not to create v2 API, but I think that's the wrong way to think (minor
and semver implicitly require us to start revving API objects more).

@lavalamp
Copy link
Member Author

Added this to the agenda for today's API Machinery SIG.

@deads2k
Copy link
Contributor

deads2k commented Oct 12, 2016

A couple questions:

  1. Am I correct in assuming that we have field level versions that are distinct for each API GroupVersion since that's the finest granularity where they are used and that would allow different groups to proceed at their own pace. Then it seems like I'd want different minor versions per-API GroupVersion so they can patch and pick changes separately.
  2. Will we use this information server-side to preserve fields that an old client stripped because it didn't recognize that they were present during update flows?
  3. How will I specify the version I used to create a particular object manifest which may be used by clients with different schema versions?

@lavalamp
Copy link
Member Author

  1. Yes, each group has its own version.
  2. Yes, that's one goal.
  3. The most obvious way would be to extend the version in the APIVersion field. It should be OK unless clients are using that to blindly construct URL paths.

@deads2k
Copy link
Contributor

deads2k commented Oct 13, 2016

It should be OK unless clients are using that to blindly construct URL paths.

As I recall, that was actually pitched as a benefit of not adding an apiGroup field to TypeMeta. I'd prefer to have a separate field for separate information. Old clients that interpret the object and drop it weren't going to understand what to do with it anyway, so I don't think that lack of roundtripping on old clients is different than current behavior for existing fields today.

@timothysc
Copy link
Member

/cc @davidopp @aveshagarwal

@aveshagarwal
Copy link
Member

@derekwaynecarr

@DirectXMan12
Copy link
Contributor

The eternal damnation of any and all badly chosen names makes me sad.

On the plus side, it does mean we can use some great GIFs...

More seriously, to clarify (also left a comment as such on the above community PR):

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, and use QuxxerQuantity instead?

That seems like it's going to cause a decent amount of redundant or strange-looking API names...

@mtaufen
Copy link
Contributor

mtaufen commented Aug 7, 2017 via email

@thockin
Copy link
Member

thockin commented Aug 29, 2017

@DirectXMan12 That's my main concern. I can buy that beta fields should not be renamed, so beta -> GA is smooth, but I suspect alpha fields will have a lower success rate. I guess we'll wait and see.

Additionally, there's no indication that you're using a beta field, which I dislike. But alas, there are not enough hours in the week to hold strong opinions on everything, so I put my trust in the SIG.

@timothysc
Copy link
Member

/cc @ncdc

@bgrant0607 bgrant0607 added the kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. label Sep 7, 2017
@k8s-github-robot
Copy link

[MILESTONENOTIFIER] Milestone Labels Complete

@lavalamp

Issue label settings:

  • sig/api-machinery: Issue will be escalated to these SIGs if needed.
  • priority/important-soon: Escalate to the issue owners and SIG owner; move out of milestone after several unsuccessful escalation attempts.
  • kind/cleanup: Adding tests, refactoring, fixing old bugs.
Additional instructions available here The commands available for adding these labels are documented here

@dims
Copy link
Member

dims commented Sep 18, 2017

@lavalamp @ncdc @thockin @timothysc @liggitt Is there anything else we need to do for 1.8 here? Can we please move the milestone if not? (or close the issue)

@mbohlool
Copy link
Contributor

mbohlool commented Sep 19, 2017

@lavalamp @ncdc @thockin @timothysc @liggitt this is a daily and friendly ping from release team. Is this still relevant to 1.8? If yes, who is actively working on it?

@lavalamp lavalamp removed this from the v1.8 milestone Sep 19, 2017
@lavalamp
Copy link
Member Author

Removing from milestone.

@warmchang
Copy link
Contributor

👍

@bgrant0607
Copy link
Member

/lifecycle frozen

@k8s-ci-robot k8s-ci-robot added the lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness. label Jan 29, 2018
@liggitt liggitt self-assigned this Oct 24, 2018
@liggitt liggitt removed their assignment Feb 18, 2021
@MadhavJivrajani
Copy link
Contributor

/remove-kind design
/kind feature

kind/design will soon be removed from k/k in favor of kind/feature. Relevant discussion can be found here: kubernetes/community#5641

@k8s-ci-robot k8s-ci-robot added kind/feature Categorizes issue or PR as related to a new feature. and removed kind/design Categorizes issue or PR as related to design. labels Jun 29, 2021
@sftim
Copy link
Contributor

sftim commented Aug 30, 2023

/sig architecture
too

@k8s-ci-robot k8s-ci-robot added the sig/architecture Categorizes an issue or PR as relevant to SIG Architecture. label Aug 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. kind/feature Categorizes issue or PR as related to a new feature. lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness. priority/important-soon Must be staffed and worked on either currently, or very soon, ideally in time for the next release. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/architecture Categorizes an issue or PR as relevant to SIG Architecture.
Projects
None yet
Development

No branches or pull requests