Document Unions, conventions for adding to Unions.

This commit is contained in:
Eric Tune 2016-01-15 14:34:46 -08:00
parent 0dc25f545f
commit 36f6049b07
2 changed files with 123 additions and 4 deletions

View File

@ -53,6 +53,7 @@ using resources with kubectl can be found in [Working with resources](../user-gu
- [Lists of named subobjects preferred over maps](#lists-of-named-subobjects-preferred-over-maps)
- [Primitive types](#primitive-types)
- [Constants](#constants)
- [Unions](#unions)
- [Lists and Simple kinds](#lists-and-simple-kinds)
- [Differing Representations](#differing-representations)
- [Verbs on Resources](#verbs-on-resources)
@ -263,6 +264,15 @@ This rule maintains the invariant that all JSON/YAML keys are fields in API obje
Some fields will have a list of allowed values (enumerations). These values will be strings, and they will be in CamelCase, with an initial uppercase letter. Examples: "ClusterFirst", "Pending", "ClientIP".
#### Unions
Sometimes, at most one of a set of fields can be set. For example, the [volumes] field of a PodSpec has 17 different volume type-specific
fields, such as `nfs` and `iscsi`. All fields in the set should be [Optional](#optional-vs-required).
Sometimes, when a new type is created, the api designer may anticipate that a union will be needed in the future, even if only one field is
allowed initially. In this case, be sure to make the field [Optional](#optional-vs-required) optional. In the validation, you may
still return an error if the sole field is unset. Do not set a default value for that field.
### Lists and Simple kinds
Every list or simple kind SHOULD have the following metadata in a nested object field called "metadata":

View File

@ -32,6 +32,38 @@ Documentation for other releases can be found at
<!-- END MUNGE: UNVERSIONED_WARNING -->
*This document is oriented at developers who want to change existing APIs.
A set of API conventions, which applies to new APIs and to changes, can be
found at [API Conventions](api-conventions.md).
**Table of Contents**
<!-- BEGIN MUNGE: GENERATED_TOC -->
- [So you want to change the API?](#so-you-want-to-change-the-api)
- [Operational overview](#operational-overview)
- [On compatibility](#on-compatibility)
- [Incompatible API changes](#incompatible-api-changes)
- [Changing versioned APIs](#changing-versioned-apis)
- [Edit types.go](#edit-typesgo)
- [Edit defaults.go](#edit-defaultsgo)
- [Edit conversion.go](#edit-conversiongo)
- [Changing the internal structures](#changing-the-internal-structures)
- [Edit types.go](#edit-typesgo)
- [Edit validation.go](#edit-validationgo)
- [Edit version conversions](#edit-version-conversions)
- [Edit deep copy files](#edit-deep-copy-files)
- [Edit json (un)marshaling code](#edit-json-unmarshaling-code)
- [Making a new API Group](#making-a-new-api-group)
- [Update the fuzzer](#update-the-fuzzer)
- [Update the semantic comparisons](#update-the-semantic-comparisons)
- [Implement your change](#implement-your-change)
- [Write end-to-end tests](#write-end-to-end-tests)
- [Examples and docs](#examples-and-docs)
- [Alpha, Beta, and Stable Versions](#alpha-beta-and-stable-versions)
- [Adding Unstable Features to Stable Versions](#adding-unstable-features-to-stable-versions)
<!-- END MUNGE: GENERATED_TOC -->
# So you want to change the API?
Before attempting a change to the API, you should familiarize yourself
@ -273,6 +305,11 @@ enumerated set *can* be a compatible change, if handled properly (treat the
removed value as deprecated but allowed). This is actually a special case of
a new representation, discussed above.
For [Unions](api-conventions.md), sets of fields where at most one should be set,
it is acceptible to add a new option to the union if the [appropriate conventions]
were followed in the original object. Removing an option requires following
the deprecation process.
## Incompatible API changes
There are times when this might be OK, but mostly we want changes that
@ -549,10 +586,6 @@ hack/update-swagger-spec.sh
The API spec changes should be in a commit separate from your other changes.
## Adding new REST objects
TODO(smarterclayton): write this.
## Alpha, Beta, and Stable Versions
New feature development proceeds through a series of stages of increasing maturity:
@ -617,6 +650,82 @@ New feature development proceeds through a series of stages of increasing maturi
- Support: API version will continue to be present for many subsequent software releases;
- Recommended Use Cases: any
### Adding Unstable Features to Stable Versions
When adding a feature to an object which is already Stable, the new fields and new behaviors
need to meet the Stable level requirements. If these cannot be met, then the new
field cannot be added to the object.
For example, consider the following object:
```go
// API v6.
type Frobber struct {
Height int `json:"height"`
Param string `json:"param"`
}
```
A developer is considering adding a new `Width` parameter, like this:
```go
// API v6.
type Frobber struct {
Height int `json:"height"`
Width int `json:"height"`
Param string `json:"param"`
}
```
However, the new feature is not stable enough to be used in a stable version (`v6`).
Some reasons for this might include:
- the final representation is undecided (e.g. should it be called `Width` or `Breadth`?)
- the implementation is not stable enough for general use (e.g. the `Area()` routine sometimes overflows.)
The developer cannot add the new field until stability is met. However, sometimes stability
cannot be met until some users try the new feature, and some users are only able or willing
to accept a released version of Kubernetes. In that case, the developer has a few options,
both of which require staging work over several releases.
A preferred option is to first make a release where the new value (`Width` in this example)
is specified via an annotation, like this:
```go
kind: frobber
version: v6
metadata:
name: myfrobber
annotations:
frobbing.alpha.kubernetes.io/width: 2
height: 4
param: "green and blue"
```
This format allows users to specify the new field, but makes it clear
that they are using a Alpha feature when they do, since the word `alpha`
is in the annotation key.
Another option is to introduce a new type with an new `alpha` or `beta` version
designator, like this:
```
// API v6alpha2
type Frobber struct {
Height int `json:"height"`
Width int `json:"height"`
Param string `json:"param"`
}
```
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 client which uses the
other version. Therefore, this is not a preferred option.
A releated issue is how a cluster manager can roll back from a new version
with a new feature, that is already being used by users. See https://github.com/kubernetes/kubernetes/issues/4855.
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/devel/api_changes.md?pixel)]()
<!-- END MUNGE: GENERATED_ANALYTICS -->