From 620cc66ead8256ad27fceb61d5d37e6d6c0c3efc Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Thu, 8 Sep 2016 16:21:58 -0400 Subject: [PATCH] Doc API group suffix, add test to catch new groups --- docs/api.md | 8 ++-- docs/design/extending-api.md | 24 +++++------ docs/devel/adding-an-APIGroup.md | 13 +++--- docs/devel/api_changes.md | 2 +- pkg/master/import_known_versions_test.go | 51 ++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 pkg/master/import_known_versions_test.go diff --git a/docs/api.md b/docs/api.md index 78b3753afa029..4d3aa674e0d38 100644 --- a/docs/api.md +++ b/docs/api.md @@ -134,10 +134,10 @@ Currently there are two API groups in use: This holds types which will probably move to another API group eventually. 1. the "componentconfig" and "metrics" API groups. - -In the future we expect that there will be more API groups, all at REST path `/apis/$API_GROUP` and -using `apiVersion: $API_GROUP/$VERSION`. We expect that there will be a way for [third parties to -create their own API groups](design/extending-api.md), and to avoid naming collisions. +In the future we expect that there will be more API groups, all at REST path `/apis/$API_GROUP` and using `apiVersion: $API_GROUP/$VERSION`. +We expect that there will be a way for [third parties to create their own API groups](design/extending-api.md). +To avoid naming collisions, third-party API groups must be a DNS name at least three segments long. +New Kubernetes API groups are suffixed with `.k8s.io` (e.g. `storage.k8s.io`, `rbac.authorization.k8s.io`). ## Enabling resources in the extensions group diff --git a/docs/design/extending-api.md b/docs/design/extending-api.md index 2a14e08efb3fd..6ce3159f7a76f 100644 --- a/docs/design/extending-api.md +++ b/docs/design/extending-api.md @@ -80,9 +80,9 @@ expected to be programmatically convertible to the name of the resource using the following conversion. Kinds are expected to be of the form ``, and the `APIVersion` for the object is expected to be `/`. To prevent collisions, it's expected that you'll -use a fully qualified domain name for the API group, e.g. `example.com`. +use a DNS name of at least three segments for the API group, e.g. `mygroup.example.com`. -For example `stable.example.com/v1` +For example `mygroup.example.com/v1` 'CamelCaseKind' is the specific type name. @@ -101,9 +101,9 @@ for ix := range kindName { } ``` -As a concrete example, the resource named `camel-case-kind.example.com` defines +As a concrete example, the resource named `camel-case-kind.mygroup.example.com` defines resources of Kind `CamelCaseKind`, in the APIGroup with the prefix -`example.com/...`. +`mygroup.example.com/...`. The reason for this is to enable rapid lookup of a `ThirdPartyResource` object given the kind information. This is also the reason why `ThirdPartyResource` is @@ -120,7 +120,7 @@ For example, if a user creates: ```yaml metadata: - name: cron-tab.stable.example.com + name: cron-tab.mygroup.example.com apiVersion: extensions/v1beta1 kind: ThirdPartyResource description: "A specification of a Pod to run on a cron style schedule" @@ -130,7 +130,7 @@ versions: ``` Then the API server will program in the new RESTful resource path: - * `/apis/stable.example.com/v1/namespaces//crontabs/...` + * `/apis/mygroup.example.com/v1/namespaces//crontabs/...` **Note: This may take a while before RESTful resource path registration happen, please always check this before you create resource instances.** @@ -142,20 +142,20 @@ Now that this schema has been created, a user can `POST`: "metadata": { "name": "my-new-cron-object" }, - "apiVersion": "stable.example.com/v1", + "apiVersion": "mygroup.example.com/v1", "kind": "CronTab", "cronSpec": "* * * * /5", "image": "my-awesome-cron-image" } ``` -to: `/apis/stable.example.com/v1/namespaces/default/crontabs` +to: `/apis/mygroup.example.com/v1/namespaces/default/crontabs` and the corresponding data will be stored into etcd by the APIServer, so that when the user issues: ``` -GET /apis/stable.example.com/v1/namespaces/default/crontabs/my-new-cron-object` +GET /apis/mygroup.example.com/v1/namespaces/default/crontabs/my-new-cron-object` ``` And when they do that, they will get back the same data, but with additional @@ -164,21 +164,21 @@ Kubernetes metadata (e.g. `resourceVersion`, `createdTimestamp`) filled in. Likewise, to list all resources, a user can issue: ``` -GET /apis/stable.example.com/v1/namespaces/default/crontabs +GET /apis/mygroup.example.com/v1/namespaces/default/crontabs ``` and get back: ```json { - "apiVersion": "stable.example.com/v1", + "apiVersion": "mygroup.example.com/v1", "kind": "CronTabList", "items": [ { "metadata": { "name": "my-new-cron-object" }, - "apiVersion": "stable.example.com/v1", + "apiVersion": "mygroup.example.com/v1", "kind": "CronTab", "cronSpec": "* * * * /5", "image": "my-awesome-cron-image" diff --git a/docs/devel/adding-an-APIGroup.md b/docs/devel/adding-an-APIGroup.md index 4b87ccf3230c4..f1bd182d0e98a 100644 --- a/docs/devel/adding-an-APIGroup.md +++ b/docs/devel/adding-an-APIGroup.md @@ -49,19 +49,19 @@ We plan on improving the way the types are factored in the future; see [#16062](https://github.com/kubernetes/kubernetes/pull/16062) for the directions in which this might evolve. -1. Create a folder in pkg/apis to hold you group. Create types.go in +1. Create a folder in pkg/apis to hold your group. Create types.go in pkg/apis/``/ and pkg/apis/``/``/ to define API objects in your group; 2. Create pkg/apis/``/{register.go, ``/register.go} to register this group's API objects to the encoding/decoding scheme (e.g., -[pkg/apis/extensions/register.go](../../pkg/apis/extensions/register.go) and -[pkg/apis/extensions/v1beta1/register.go](../../pkg/apis/extensions/v1beta1/register.go); +[pkg/apis/authentication/register.go](../../pkg/apis/authentication/register.go) and +[pkg/apis/authentication/v1beta1/register.go](../../pkg/apis/authentication/v1beta1/register.go); 3. Add a pkg/apis/``/install/install.go, which is responsible for adding the group to the `latest` package, so that other packages can access the group's meta through `latest.Group`. You probably only need to change the name of group -and version in the [example](../../pkg/apis/extensions/install/install.go)). You +and version in the [example](../../pkg/apis/authentication/install/install.go)). You need to import this `install` package in {pkg/master, pkg/client/unversioned}/import_known_versions.go, if you want to make your group accessible to other packages in the kube-apiserver binary, binaries that uses @@ -83,7 +83,10 @@ cmd/libs/go2idl/ tool. with the comment `// +k8s:conversion-gen=`, to catch the attention of our generation tools. For most APIs the only target you need is `k8s.io/kubernetes/pkg/apis/` (your internal API). - 4. Run hack/update-all.sh. + 3. Make sure your `pkg/apis/` and `pkg/apis//` directories + have a doc.go file with the comment `+groupName=.k8s.io`, to correctly + generate the DNS-suffixed group name. + 5. Run hack/update-all.sh. 2. Generate files for Ugorji codec: diff --git a/docs/devel/api_changes.md b/docs/devel/api_changes.md index 0b0b7987782af..afdbaae7be394 100755 --- a/docs/devel/api_changes.md +++ b/docs/devel/api_changes.md @@ -519,7 +519,7 @@ hack/update-codecgen.sh This section is under construction, as we make the tooling completely generic. At the moment, you'll have to make a new directory under `pkg/apis/`; copy the -directory structure from `pkg/apis/extensions`. Add the new group/version to all +directory structure from `pkg/apis/authentication`. Add the new group/version to all of the `hack/{verify,update}-generated-{deep-copy,conversions,swagger}.sh` files in the appropriate places--it should just require adding your new group/version to a bash array. See [docs on adding an API group](adding-an-APIGroup.md) for diff --git a/pkg/master/import_known_versions_test.go b/pkg/master/import_known_versions_test.go new file mode 100644 index 0000000000000..e3b977c8dc03d --- /dev/null +++ b/pkg/master/import_known_versions_test.go @@ -0,0 +1,51 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package master + +import ( + "strings" + "testing" + + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/util/sets" +) + +func TestGroupVersions(t *testing.T) { + // legacyUnsuffixedGroups contains the groups released prior to deciding that kubernetes API groups should be dns-suffixed + // new groups should be suffixed with ".k8s.io" (https://github.com/kubernetes/kubernetes/pull/31887#issuecomment-244462396) + legacyUnsuffixedGroups := sets.NewString( + "", + "apps", + "autoscaling", + "batch", + "componentconfig", + "extensions", + "federation", + "policy", + ) + + // No new groups should be added to the legacyUnsuffixedGroups exclusion list + if len(legacyUnsuffixedGroups) != 8 { + t.Errorf("No additional unnamespaced groups should be created") + } + + for _, gv := range registered.RegisteredGroupVersions() { + if !strings.HasSuffix(gv.Group, ".k8s.io") && !legacyUnsuffixedGroups.Has(gv.Group) { + t.Errorf("Group %s does not have the standard kubernetes API group suffix of .k8s.io", gv.Group) + } + } +}