From 0ac10c6cc2ab18c6543e845d0a2aee8c4500177b Mon Sep 17 00:00:00 2001 From: Prashanth Balasubramanian Date: Fri, 15 Apr 2016 15:30:15 -0700 Subject: [PATCH] PetSet type, apps apigroup --- api/swagger-spec/apps.json | 110 + api/swagger-spec/apps_v1alpha1.json | 2517 +++++++++++++++++ api/swagger-spec/resourceListing.json | 8 + cmd/kube-apiserver/app/server.go | 26 + cmd/libs/go2idl/conversion-gen/main.go | 2 + cmd/libs/go2idl/deepcopy-gen/main.go | 2 + .../go2idl/go-to-protobuf/protobuf/cmd.go | 1 + contrib/completions/bash/kubectl | 10 + docs/admin/kube-apiserver.md | 4 +- hack/after-build/update-swagger-spec.sh | 2 +- hack/test-cmd.sh | 8 +- hack/test-go.sh | 4 +- hack/test-integration.sh | 8 +- hack/update-api-reference-docs.sh | 4 +- hack/update-generated-swagger-docs.sh | 2 +- pkg/api/testapi/testapi.go | 11 + pkg/apis/apps/deep_copy_generated.go | 117 + pkg/apis/apps/install/install.go | 125 + pkg/apis/apps/register.go | 57 + pkg/apis/apps/types.generated.go | 1636 +++++++++++ pkg/apis/apps/types.go | 94 + pkg/apis/apps/v1alpha1/conversion.go | 125 + .../apps/v1alpha1/conversion_generated.go | 186 ++ pkg/apis/apps/v1alpha1/deep_copy_generated.go | 124 + pkg/apis/apps/v1alpha1/defaulting.go | 44 + pkg/apis/apps/v1alpha1/doc.go | 18 + pkg/apis/apps/v1alpha1/register.go | 49 + pkg/apis/apps/v1alpha1/types.generated.go | 1666 +++++++++++ pkg/apis/apps/v1alpha1/types.go | 94 + .../v1alpha1/types_swagger_doc_generated.go | 71 + pkg/apis/apps/validation/validation.go | 110 + pkg/apis/apps/validation/validation_test.go | 379 +++ .../import_known_versions.go | 1 + pkg/client/unversioned/apps.go | 82 + pkg/client/unversioned/client.go | 5 + pkg/client/unversioned/helper.go | 11 +- .../unversioned/import_known_versions.go | 1 + pkg/client/unversioned/pet_sets.go | 100 + pkg/client/unversioned/pet_sets_test.go | 165 ++ pkg/kubectl/cmd/util/factory.go | 10 + pkg/kubectl/resource_printer.go | 51 + pkg/master/import_known_versions.go | 1 + pkg/master/master.go | 58 +- pkg/master/master_test.go | 19 +- pkg/registry/cachesize/cachesize.go | 2 + pkg/registry/petset/doc.go | 17 + pkg/registry/petset/etcd/etcd.go | 96 + pkg/registry/petset/etcd/etcd_test.go | 182 ++ pkg/registry/petset/strategy.go | 142 + pkg/registry/petset/strategy_test.go | 136 + test/integration/framework/etcd_utils.go | 7 + test/integration/framework/master_utils.go | 4 + test/integration/master_test.go | 4 + 53 files changed, 8688 insertions(+), 20 deletions(-) create mode 100644 api/swagger-spec/apps.json create mode 100644 api/swagger-spec/apps_v1alpha1.json create mode 100644 pkg/apis/apps/deep_copy_generated.go create mode 100644 pkg/apis/apps/install/install.go create mode 100644 pkg/apis/apps/register.go create mode 100644 pkg/apis/apps/types.generated.go create mode 100644 pkg/apis/apps/types.go create mode 100644 pkg/apis/apps/v1alpha1/conversion.go create mode 100644 pkg/apis/apps/v1alpha1/conversion_generated.go create mode 100644 pkg/apis/apps/v1alpha1/deep_copy_generated.go create mode 100644 pkg/apis/apps/v1alpha1/defaulting.go create mode 100644 pkg/apis/apps/v1alpha1/doc.go create mode 100644 pkg/apis/apps/v1alpha1/register.go create mode 100644 pkg/apis/apps/v1alpha1/types.generated.go create mode 100644 pkg/apis/apps/v1alpha1/types.go create mode 100644 pkg/apis/apps/v1alpha1/types_swagger_doc_generated.go create mode 100644 pkg/apis/apps/validation/validation.go create mode 100644 pkg/apis/apps/validation/validation_test.go create mode 100644 pkg/client/unversioned/apps.go create mode 100644 pkg/client/unversioned/pet_sets.go create mode 100644 pkg/client/unversioned/pet_sets_test.go create mode 100644 pkg/registry/petset/doc.go create mode 100644 pkg/registry/petset/etcd/etcd.go create mode 100644 pkg/registry/petset/etcd/etcd_test.go create mode 100644 pkg/registry/petset/strategy.go create mode 100644 pkg/registry/petset/strategy_test.go diff --git a/api/swagger-spec/apps.json b/api/swagger-spec/apps.json new file mode 100644 index 00000000000..0a5e9df70cf --- /dev/null +++ b/api/swagger-spec/apps.json @@ -0,0 +1,110 @@ +{ + "swaggerVersion": "1.2", + "apiVersion": "", + "basePath": "https://10.10.10.10:443", + "resourcePath": "/apis/apps", + "apis": [ + { + "path": "/apis/apps", + "description": "get information of a group", + "operations": [ + { + "type": "unversioned.APIGroup", + "method": "GET", + "summary": "get information of a group", + "nickname": "getAPIGroup", + "parameters": [], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ] + } + ] + } + ], + "models": { + "unversioned.APIGroup": { + "id": "unversioned.APIGroup", + "description": "APIGroup contains the name, the supported versions, and the preferred version of a group.", + "required": [ + "name", + "versions", + "serverAddressByClientCIDRs" + ], + "properties": { + "kind": { + "type": "string", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + }, + "apiVersion": { + "type": "string", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources" + }, + "name": { + "type": "string", + "description": "name is the name of the group." + }, + "versions": { + "type": "array", + "items": { + "$ref": "unversioned.GroupVersionForDiscovery" + }, + "description": "versions are the versions supported in this group." + }, + "preferredVersion": { + "$ref": "unversioned.GroupVersionForDiscovery", + "description": "preferredVersion is the version preferred by the API server, which probably is the storage version." + }, + "serverAddressByClientCIDRs": { + "type": "array", + "items": { + "$ref": "unversioned.ServerAddressByClientCIDR" + }, + "description": "a map of client CIDR to server address that is serving this group. This is to help clients reach servers in the most network-efficient way possible. Clients can use the appropriate server address as per the CIDR that they match. In case of multiple matches, clients should use the longest matching CIDR. The server returns only those CIDRs that it thinks that the client can match. For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP. Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP." + } + } + }, + "unversioned.GroupVersionForDiscovery": { + "id": "unversioned.GroupVersionForDiscovery", + "description": "GroupVersion contains the \"group/version\" and \"version\" string of a version. It is made a struct to keep extensiblity.", + "required": [ + "groupVersion", + "version" + ], + "properties": { + "groupVersion": { + "type": "string", + "description": "groupVersion specifies the API group and version in the form \"group/version\"" + }, + "version": { + "type": "string", + "description": "version specifies the version in the form of \"version\". This is to save the clients the trouble of splitting the GroupVersion." + } + } + }, + "unversioned.ServerAddressByClientCIDR": { + "id": "unversioned.ServerAddressByClientCIDR", + "description": "ServerAddressByClientCIDR helps the client to determine the server address that they should use, depending on the clientCIDR that they match.", + "required": [ + "clientCIDR", + "serverAddress" + ], + "properties": { + "clientCIDR": { + "type": "string", + "description": "The CIDR with which clients can match their IP to figure out the server address that they should use." + }, + "serverAddress": { + "type": "string", + "description": "Address of this server, suitable for a client that matches the above CIDR. This can be a hostname, hostname:port, IP or IP:port." + } + } + } + } + } diff --git a/api/swagger-spec/apps_v1alpha1.json b/api/swagger-spec/apps_v1alpha1.json new file mode 100644 index 00000000000..faddc80b0bc --- /dev/null +++ b/api/swagger-spec/apps_v1alpha1.json @@ -0,0 +1,2517 @@ +{ + "swaggerVersion": "1.2", + "apiVersion": "apps/v1alpha1", + "basePath": "https://10.10.10.10:443", + "resourcePath": "/apis/apps/v1alpha1", + "apis": [ + { + "path": "/apis/apps/v1alpha1/namespaces/{namespace}/petsets", + "description": "API at /apis/apps/v1alpha1", + "operations": [ + { + "type": "v1alpha1.PetSetList", + "method": "GET", + "summary": "list or watch objects of kind PetSet", + "nickname": "listNamespacedPetSet", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "labelSelector", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "fieldSelector", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "boolean", + "paramType": "query", + "name": "watch", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "resourceVersion", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history.", + "required": false, + "allowMultiple": false + }, + { + "type": "integer", + "paramType": "query", + "name": "timeoutSeconds", + "description": "Timeout for the list/watch call.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "namespace", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PetSetList" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + }, + { + "type": "v1alpha1.PetSet", + "method": "POST", + "summary": "create a PetSet", + "nickname": "createNamespacedPetSet", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "v1alpha1.PetSet", + "paramType": "body", + "name": "body", + "description": "", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "namespace", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PetSet" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + }, + { + "type": "unversioned.Status", + "method": "DELETE", + "summary": "delete collection of PetSet", + "nickname": "deletecollectionNamespacedPetSet", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "labelSelector", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "fieldSelector", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "boolean", + "paramType": "query", + "name": "watch", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "resourceVersion", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history.", + "required": false, + "allowMultiple": false + }, + { + "type": "integer", + "paramType": "query", + "name": "timeoutSeconds", + "description": "Timeout for the list/watch call.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "namespace", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "unversioned.Status" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/apps/v1alpha1/watch/namespaces/{namespace}/petsets", + "description": "API at /apis/apps/v1alpha1", + "operations": [ + { + "type": "*versioned.Event", + "method": "GET", + "summary": "watch individual changes to a list of PetSet", + "nickname": "watchNamespacedPetSetList", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "labelSelector", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "fieldSelector", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "boolean", + "paramType": "query", + "name": "watch", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "resourceVersion", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history.", + "required": false, + "allowMultiple": false + }, + { + "type": "integer", + "paramType": "query", + "name": "timeoutSeconds", + "description": "Timeout for the list/watch call.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "namespace", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "*versioned.Event" + } + ], + "produces": [ + "application/json", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/apps/v1alpha1/namespaces/{namespace}/petsets/{name}", + "description": "API at /apis/apps/v1alpha1", + "operations": [ + { + "type": "v1alpha1.PetSet", + "method": "GET", + "summary": "read the specified PetSet", + "nickname": "readNamespacedPetSet", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "boolean", + "paramType": "query", + "name": "export", + "description": "Should this value be exported. Export strips fields that a user can not specify.", + "required": false, + "allowMultiple": false + }, + { + "type": "boolean", + "paramType": "query", + "name": "exact", + "description": "Should the export be exact. Exact export maintains cluster-specific fields like 'Namespace'", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "namespace", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "name", + "description": "name of the PetSet", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PetSet" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + }, + { + "type": "v1alpha1.PetSet", + "method": "PUT", + "summary": "replace the specified PetSet", + "nickname": "replaceNamespacedPetSet", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "v1alpha1.PetSet", + "paramType": "body", + "name": "body", + "description": "", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "namespace", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "name", + "description": "name of the PetSet", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PetSet" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + }, + { + "type": "v1alpha1.PetSet", + "method": "PATCH", + "summary": "partially update the specified PetSet", + "nickname": "patchNamespacedPetSet", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "unversioned.Patch", + "paramType": "body", + "name": "body", + "description": "", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "namespace", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "name", + "description": "name of the PetSet", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PetSet" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "application/json-patch+json", + "application/merge-patch+json", + "application/strategic-merge-patch+json" + ] + }, + { + "type": "unversioned.Status", + "method": "DELETE", + "summary": "delete a PetSet", + "nickname": "deleteNamespacedPetSet", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "v1.DeleteOptions", + "paramType": "body", + "name": "body", + "description": "", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "namespace", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "name", + "description": "name of the PetSet", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "unversioned.Status" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/apps/v1alpha1/watch/namespaces/{namespace}/petsets/{name}", + "description": "API at /apis/apps/v1alpha1", + "operations": [ + { + "type": "*versioned.Event", + "method": "GET", + "summary": "watch changes to an object of kind PetSet", + "nickname": "watchNamespacedPetSet", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "labelSelector", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "fieldSelector", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "boolean", + "paramType": "query", + "name": "watch", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "resourceVersion", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history.", + "required": false, + "allowMultiple": false + }, + { + "type": "integer", + "paramType": "query", + "name": "timeoutSeconds", + "description": "Timeout for the list/watch call.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "namespace", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "name", + "description": "name of the PetSet", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "*versioned.Event" + } + ], + "produces": [ + "application/json", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/apps/v1alpha1/petsets", + "description": "API at /apis/apps/v1alpha1", + "operations": [ + { + "type": "v1alpha1.PetSetList", + "method": "GET", + "summary": "list or watch objects of kind PetSet", + "nickname": "listNamespacedPetSet", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "labelSelector", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "fieldSelector", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "boolean", + "paramType": "query", + "name": "watch", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "resourceVersion", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history.", + "required": false, + "allowMultiple": false + }, + { + "type": "integer", + "paramType": "query", + "name": "timeoutSeconds", + "description": "Timeout for the list/watch call.", + "required": false, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PetSetList" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/apps/v1alpha1/watch/petsets", + "description": "API at /apis/apps/v1alpha1", + "operations": [ + { + "type": "*versioned.Event", + "method": "GET", + "summary": "watch individual changes to a list of PetSet", + "nickname": "watchNamespacedPetSetList", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "labelSelector", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "fieldSelector", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "required": false, + "allowMultiple": false + }, + { + "type": "boolean", + "paramType": "query", + "name": "watch", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "required": false, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "query", + "name": "resourceVersion", + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history.", + "required": false, + "allowMultiple": false + }, + { + "type": "integer", + "paramType": "query", + "name": "timeoutSeconds", + "description": "Timeout for the list/watch call.", + "required": false, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "*versioned.Event" + } + ], + "produces": [ + "application/json", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/apps/v1alpha1/namespaces/{namespace}/petsets/{name}/status", + "description": "API at /apis/apps/v1alpha1", + "operations": [ + { + "type": "v1alpha1.PetSet", + "method": "PUT", + "summary": "replace status of the specified PetSet", + "nickname": "replaceNamespacedPetSetStatus", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "v1alpha1.PetSet", + "paramType": "body", + "name": "body", + "description": "", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "namespace", + "description": "object name and auth scope, such as for teams and projects", + "required": true, + "allowMultiple": false + }, + { + "type": "string", + "paramType": "path", + "name": "name", + "description": "name of the PetSet", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PetSet" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/apps/v1alpha1", + "description": "API at /apis/apps/v1alpha1", + "operations": [ + { + "type": "unversioned.APIResourceList", + "method": "GET", + "summary": "get available resources", + "nickname": "getAPIResources", + "parameters": [], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ] + } + ] + } + ], + "models": { + "v1alpha1.PetSetList": { + "id": "v1alpha1.PetSetList", + "description": "PetSetList is a collection of PetSets.", + "required": [ + "items" + ], + "properties": { + "kind": { + "type": "string", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + }, + "apiVersion": { + "type": "string", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources" + }, + "metadata": { + "$ref": "unversioned.ListMeta" + }, + "items": { + "type": "array", + "items": { + "$ref": "v1alpha1.PetSet" + } + } + } + }, + "unversioned.ListMeta": { + "id": "unversioned.ListMeta", + "description": "ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}.", + "properties": { + "selfLink": { + "type": "string", + "description": "SelfLink is a URL representing this object. Populated by the system. Read-only." + }, + "resourceVersion": { + "type": "string", + "description": "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#concurrency-control-and-consistency" + } + } + }, + "v1alpha1.PetSet": { + "id": "v1alpha1.PetSet", + "description": "PetSet represents a set of pods with consistent identities. Identities are defined as:\n - Network: A single stable DNS and hostname.\n - Storage: As many VolumeClaims as requested.\nThe PetSet guarantees that a given network identity will always map to the same storage identity. PetSet is currently in alpha and subject to change without notice.", + "properties": { + "kind": { + "type": "string", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + }, + "apiVersion": { + "type": "string", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources" + }, + "metadata": { + "$ref": "v1.ObjectMeta" + }, + "spec": { + "$ref": "v1alpha1.PetSetSpec", + "description": "Spec defines the desired identities of pets in this set." + }, + "status": { + "$ref": "v1alpha1.PetSetStatus", + "description": "Status is the current status of Pets in this PetSet. This data may be out of date by some window of time." + } + } + }, + "v1.ObjectMeta": { + "id": "v1.ObjectMeta", + "description": "ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create.", + "properties": { + "name": { + "type": "string", + "description": "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names" + }, + "generateName": { + "type": "string", + "description": "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#idempotency" + }, + "namespace": { + "type": "string", + "description": "Namespace defines the space within each name must be unique. An empty namespace is equivalent to the \"default\" namespace, but \"default\" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty.\n\nMust be a DNS_LABEL. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/namespaces.md" + }, + "selfLink": { + "type": "string", + "description": "SelfLink is a URL representing this object. Populated by the system. Read-only." + }, + "uid": { + "type": "string", + "description": "UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations.\n\nPopulated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#uids" + }, + "resourceVersion": { + "type": "string", + "description": "An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources.\n\nPopulated by the system. Read-only. Value must be treated as opaque by clients and . More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#concurrency-control-and-consistency" + }, + "generation": { + "type": "integer", + "format": "int64", + "description": "A sequence number representing a specific generation of the desired state. Populated by the system. Read-only." + }, + "creationTimestamp": { + "type": "string", + "description": "CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata" + }, + "deletionTimestamp": { + "type": "string", + "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource will be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field. Once set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. Once the resource is deleted in the API, the Kubelet will send a hard termination signal to the container. If not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested. Read-only. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata" + }, + "deletionGracePeriodSeconds": { + "type": "integer", + "format": "int64", + "description": "Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only." + }, + "labels": { + "type": "object", + "description": "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md" + }, + "annotations": { + "type": "object", + "description": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: http://releases.k8s.io/HEAD/docs/user-guide/annotations.md" + } + } + }, + "v1alpha1.PetSetSpec": { + "id": "v1alpha1.PetSetSpec", + "description": "A PetSetSpec is the specification of a PetSet.", + "required": [ + "template", + "serviceName" + ], + "properties": { + "replicas": { + "type": "integer", + "format": "int32", + "description": "Replicas is the desired number of replicas of the given Template. These are replicas in the sense that they are instantiations of the same Template, but individual replicas also have a consistent identity. If unspecified, defaults to 1." + }, + "selector": { + "$ref": "unversioned.LabelSelector", + "description": "Selector is a label query over pods that should match the replica count. If empty, defaulted to labels on the pod template. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors" + }, + "template": { + "$ref": "v1.PodTemplateSpec", + "description": "Template is the object that describes the pod that will be created if insufficient replicas are detected. Each pod stamped out by the PetSet will fulfill this Template, but have a unique identity from the rest of the PetSet." + }, + "volumeClaimTemplates": { + "type": "array", + "items": { + "$ref": "v1.PersistentVolumeClaim" + }, + "description": "VolumeClaimTemplates is a list of claims that pets are allowed to reference. The PetSet controller is responsible for mapping network identities to claims in a way that maintains the identity of a pet. Every claim in this list must have at least one matching (by name) volumeMount in one container in the template. A claim in this list takes precedence over any volumes in the template, with the same name." + }, + "serviceName": { + "type": "string", + "description": "ServiceName is the name of the service that governs this PetSet. This service must exist before the PetSet, and is responsible for the network identity of the set. Pets get DNS/hostnames that follow the pattern: pet-specific-string.serviceName.default.svc.cluster.local where \"pet-specific-string\" is managed by the PetSet controller." + } + } + }, + "unversioned.LabelSelector": { + "id": "unversioned.LabelSelector", + "description": "A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects.", + "properties": { + "matchLabels": { + "type": "object", + "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed." + }, + "matchExpressions": { + "type": "array", + "items": { + "$ref": "unversioned.LabelSelectorRequirement" + }, + "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed." + } + } + }, + "unversioned.LabelSelectorRequirement": { + "id": "unversioned.LabelSelectorRequirement", + "description": "A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.", + "required": [ + "key", + "operator" + ], + "properties": { + "key": { + "type": "string", + "description": "key is the label key that the selector applies to." + }, + "operator": { + "type": "string", + "description": "operator represents a key's relationship to a set of values. Valid operators ard In, NotIn, Exists and DoesNotExist." + }, + "values": { + "type": "array", + "items": { + "type": "string" + }, + "description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch." + } + } + }, + "v1.PodTemplateSpec": { + "id": "v1.PodTemplateSpec", + "description": "PodTemplateSpec describes the data a pod should have when created from a template", + "properties": { + "metadata": { + "$ref": "v1.ObjectMeta", + "description": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata" + }, + "spec": { + "$ref": "v1.PodSpec", + "description": "Specification of the desired behavior of the pod. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status" + } + } + }, + "v1.PodSpec": { + "id": "v1.PodSpec", + "description": "PodSpec is a description of a pod.", + "required": [ + "containers" + ], + "properties": { + "volumes": { + "type": "array", + "items": { + "$ref": "v1.Volume" + }, + "description": "List of volumes that can be mounted by containers belonging to the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md" + }, + "containers": { + "type": "array", + "items": { + "$ref": "v1.Container" + }, + "description": "List of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/containers.md" + }, + "restartPolicy": { + "type": "string", + "description": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#restartpolicy" + }, + "terminationGracePeriodSeconds": { + "type": "integer", + "format": "int64", + "description": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds." + }, + "activeDeadlineSeconds": { + "type": "integer", + "format": "int64", + "description": "Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer." + }, + "dnsPolicy": { + "type": "string", + "description": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\"." + }, + "nodeSelector": { + "type": "object", + "description": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: http://releases.k8s.io/HEAD/docs/user-guide/node-selection/README.md" + }, + "serviceAccountName": { + "type": "string", + "description": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md" + }, + "serviceAccount": { + "type": "string", + "description": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead." + }, + "nodeName": { + "type": "string", + "description": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements." + }, + "hostNetwork": { + "type": "boolean", + "description": "Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false." + }, + "hostPID": { + "type": "boolean", + "description": "Use the host's pid namespace. Optional: Default to false." + }, + "hostIPC": { + "type": "boolean", + "description": "Use the host's ipc namespace. Optional: Default to false." + }, + "securityContext": { + "$ref": "v1.PodSecurityContext", + "description": "SecurityContext holds pod-level security attributes and common container settings. Optional: Defaults to empty. See type description for default values of each field." + }, + "imagePullSecrets": { + "type": "array", + "items": { + "$ref": "v1.LocalObjectReference" + }, + "description": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md#specifying-imagepullsecrets-on-a-pod" + } + } + }, + "v1.Volume": { + "id": "v1.Volume", + "description": "Volume represents a named volume in a pod that may be accessed by any container in the pod.", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "Volume's name. Must be a DNS_LABEL and unique within the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names" + }, + "hostPath": { + "$ref": "v1.HostPathVolumeSource", + "description": "HostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#hostpath" + }, + "emptyDir": { + "$ref": "v1.EmptyDirVolumeSource", + "description": "EmptyDir represents a temporary directory that shares a pod's lifetime. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#emptydir" + }, + "gcePersistentDisk": { + "$ref": "v1.GCEPersistentDiskVolumeSource", + "description": "GCEPersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk" + }, + "awsElasticBlockStore": { + "$ref": "v1.AWSElasticBlockStoreVolumeSource", + "description": "AWSElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#awselasticblockstore" + }, + "gitRepo": { + "$ref": "v1.GitRepoVolumeSource", + "description": "GitRepo represents a git repository at a particular revision." + }, + "secret": { + "$ref": "v1.SecretVolumeSource", + "description": "Secret represents a secret that should populate this volume. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#secrets" + }, + "nfs": { + "$ref": "v1.NFSVolumeSource", + "description": "NFS represents an NFS mount on the host that shares a pod's lifetime More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#nfs" + }, + "iscsi": { + "$ref": "v1.ISCSIVolumeSource", + "description": "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/HEAD/examples/iscsi/README.md" + }, + "glusterfs": { + "$ref": "v1.GlusterfsVolumeSource", + "description": "Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: http://releases.k8s.io/HEAD/examples/glusterfs/README.md" + }, + "persistentVolumeClaim": { + "$ref": "v1.PersistentVolumeClaimVolumeSource", + "description": "PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistentvolumeclaims" + }, + "rbd": { + "$ref": "v1.RBDVolumeSource", + "description": "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md" + }, + "flexVolume": { + "$ref": "v1.FlexVolumeSource", + "description": "FlexVolume represents a generic volume resource that is provisioned/attached using a exec based plugin. This is an alpha feature and may change in future." + }, + "cinder": { + "$ref": "v1.CinderVolumeSource", + "description": "Cinder represents a cinder volume attached and mounted on kubelets host machine More info: http://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md" + }, + "cephfs": { + "$ref": "v1.CephFSVolumeSource", + "description": "CephFS represents a Ceph FS mount on the host that shares a pod's lifetime" + }, + "flocker": { + "$ref": "v1.FlockerVolumeSource", + "description": "Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running" + }, + "downwardAPI": { + "$ref": "v1.DownwardAPIVolumeSource", + "description": "DownwardAPI represents downward API about the pod that should populate this volume" + }, + "fc": { + "$ref": "v1.FCVolumeSource", + "description": "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod." + }, + "azureFile": { + "$ref": "v1.AzureFileVolumeSource", + "description": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod." + }, + "configMap": { + "$ref": "v1.ConfigMapVolumeSource", + "description": "ConfigMap represents a configMap that should populate this volume" + } + } + }, + "v1.HostPathVolumeSource": { + "id": "v1.HostPathVolumeSource", + "description": "Represents a host path mapped into a pod. Host path volumes do not support ownership management or SELinux relabeling.", + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string", + "description": "Path of the directory on the host. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#hostpath" + } + } + }, + "v1.EmptyDirVolumeSource": { + "id": "v1.EmptyDirVolumeSource", + "description": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.", + "properties": { + "medium": { + "type": "string", + "description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#emptydir" + } + } + }, + "v1.GCEPersistentDiskVolumeSource": { + "id": "v1.GCEPersistentDiskVolumeSource", + "description": "Represents a Persistent Disk resource in Google Compute Engine.\n\nA GCE PD must exist before mounting to a container. The disk must also be in the same GCE project and zone as the kubelet. A GCE PD can only be mounted as read/write once or read-only many times. GCE PDs support ownership management and SELinux relabeling.", + "required": [ + "pdName" + ], + "properties": { + "pdName": { + "type": "string", + "description": "Unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk" + }, + "fsType": { + "type": "string", + "description": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk" + }, + "partition": { + "type": "integer", + "format": "int32", + "description": "The partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty). More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk" + }, + "readOnly": { + "type": "boolean", + "description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk" + } + } + }, + "v1.AWSElasticBlockStoreVolumeSource": { + "id": "v1.AWSElasticBlockStoreVolumeSource", + "description": "Represents a Persistent Disk resource in AWS.\n\nAn AWS EBS disk must exist before mounting to a container. The disk must also be in the same AWS zone as the kubelet. An AWS EBS disk can only be mounted as read/write once. AWS EBS volumes support ownership management and SELinux relabeling.", + "required": [ + "volumeID" + ], + "properties": { + "volumeID": { + "type": "string", + "description": "Unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#awselasticblockstore" + }, + "fsType": { + "type": "string", + "description": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#awselasticblockstore" + }, + "partition": { + "type": "integer", + "format": "int32", + "description": "The partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty)." + }, + "readOnly": { + "type": "boolean", + "description": "Specify \"true\" to force and set the ReadOnly property in VolumeMounts to \"true\". If omitted, the default is \"false\". More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#awselasticblockstore" + } + } + }, + "v1.GitRepoVolumeSource": { + "id": "v1.GitRepoVolumeSource", + "description": "Represents a volume that is populated with the contents of a git repository. Git repo volumes do not support ownership management. Git repo volumes support SELinux relabeling.", + "required": [ + "repository" + ], + "properties": { + "repository": { + "type": "string", + "description": "Repository URL" + }, + "revision": { + "type": "string", + "description": "Commit hash for the specified revision." + }, + "directory": { + "type": "string", + "description": "Target directory name. Must not contain or start with '..'. If '.' is supplied, the volume directory will be the git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name." + } + } + }, + "v1.SecretVolumeSource": { + "id": "v1.SecretVolumeSource", + "description": "Adapts a Secret into a volume.\n\nThe contents of the target Secret's Data field will be presented in a volume as files using the keys in the Data field as the file names. Secret volumes support ownership management and SELinux relabeling.", + "properties": { + "secretName": { + "type": "string", + "description": "Name of the secret in the pod's namespace to use. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#secrets" + } + } + }, + "v1.NFSVolumeSource": { + "id": "v1.NFSVolumeSource", + "description": "Represents an NFS mount that lasts the lifetime of a pod. NFS volumes do not support ownership management or SELinux relabeling.", + "required": [ + "server", + "path" + ], + "properties": { + "server": { + "type": "string", + "description": "Server is the hostname or IP address of the NFS server. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#nfs" + }, + "path": { + "type": "string", + "description": "Path that is exported by the NFS server. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#nfs" + }, + "readOnly": { + "type": "boolean", + "description": "ReadOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#nfs" + } + } + }, + "v1.ISCSIVolumeSource": { + "id": "v1.ISCSIVolumeSource", + "description": "Represents an ISCSI disk. ISCSI volumes can only be mounted as read/write once. ISCSI volumes support ownership management and SELinux relabeling.", + "required": [ + "targetPortal", + "iqn", + "lun" + ], + "properties": { + "targetPortal": { + "type": "string", + "description": "iSCSI target portal. The portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260)." + }, + "iqn": { + "type": "string", + "description": "Target iSCSI Qualified Name." + }, + "lun": { + "type": "integer", + "format": "int32", + "description": "iSCSI target lun number." + }, + "iscsiInterface": { + "type": "string", + "description": "Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport." + }, + "fsType": { + "type": "string", + "description": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#iscsi" + }, + "readOnly": { + "type": "boolean", + "description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false." + } + } + }, + "v1.GlusterfsVolumeSource": { + "id": "v1.GlusterfsVolumeSource", + "description": "Represents a Glusterfs mount that lasts the lifetime of a pod. Glusterfs volumes do not support ownership management or SELinux relabeling.", + "required": [ + "endpoints", + "path" + ], + "properties": { + "endpoints": { + "type": "string", + "description": "EndpointsName is the endpoint name that details Glusterfs topology. More info: http://releases.k8s.io/HEAD/examples/glusterfs/README.md#create-a-pod" + }, + "path": { + "type": "string", + "description": "Path is the Glusterfs volume path. More info: http://releases.k8s.io/HEAD/examples/glusterfs/README.md#create-a-pod" + }, + "readOnly": { + "type": "boolean", + "description": "ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: http://releases.k8s.io/HEAD/examples/glusterfs/README.md#create-a-pod" + } + } + }, + "v1.PersistentVolumeClaimVolumeSource": { + "id": "v1.PersistentVolumeClaimVolumeSource", + "description": "PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace. This volume finds the bound PV and mounts that volume for the pod. A PersistentVolumeClaimVolumeSource is, essentially, a wrapper around another type of volume that is owned by someone else (the system).", + "required": [ + "claimName" + ], + "properties": { + "claimName": { + "type": "string", + "description": "ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistentvolumeclaims" + }, + "readOnly": { + "type": "boolean", + "description": "Will force the ReadOnly setting in VolumeMounts. Default false." + } + } + }, + "v1.RBDVolumeSource": { + "id": "v1.RBDVolumeSource", + "description": "Represents a Rados Block Device mount that lasts the lifetime of a pod. RBD volumes support ownership management and SELinux relabeling.", + "required": [ + "monitors", + "image", + "pool", + "user", + "keyring", + "secretRef" + ], + "properties": { + "monitors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A collection of Ceph monitors. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it" + }, + "image": { + "type": "string", + "description": "The rados image name. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it" + }, + "fsType": { + "type": "string", + "description": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#rbd" + }, + "pool": { + "type": "string", + "description": "The rados pool name. Default is rbd. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it." + }, + "user": { + "type": "string", + "description": "The rados user name. Default is admin. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it" + }, + "keyring": { + "type": "string", + "description": "Keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it" + }, + "secretRef": { + "$ref": "v1.LocalObjectReference", + "description": "SecretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is empty. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it" + }, + "readOnly": { + "type": "boolean", + "description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it" + } + } + }, + "v1.LocalObjectReference": { + "id": "v1.LocalObjectReference", + "description": "LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.", + "properties": { + "name": { + "type": "string", + "description": "Name of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names" + } + } + }, + "v1.FlexVolumeSource": { + "id": "v1.FlexVolumeSource", + "description": "FlexVolume represents a generic volume resource that is provisioned/attached using a exec based plugin. This is an alpha feature and may change in future.", + "required": [ + "driver" + ], + "properties": { + "driver": { + "type": "string", + "description": "Driver is the name of the driver to use for this volume." + }, + "fsType": { + "type": "string", + "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script." + }, + "secretRef": { + "$ref": "v1.LocalObjectReference", + "description": "Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts." + }, + "readOnly": { + "type": "boolean", + "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts." + }, + "options": { + "type": "object", + "description": "Optional: Extra command options if any." + } + } + }, + "v1.CinderVolumeSource": { + "id": "v1.CinderVolumeSource", + "description": "Represents a cinder volume resource in Openstack. A Cinder volume must exist before mounting to a container. The volume must also be in the same region as the kubelet. Cinder volumes support ownership management and SELinux relabeling.", + "required": [ + "volumeID" + ], + "properties": { + "volumeID": { + "type": "string", + "description": "volume id used to identify the volume in cinder More info: http://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md" + }, + "fsType": { + "type": "string", + "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md" + }, + "readOnly": { + "type": "boolean", + "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: http://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md" + } + } + }, + "v1.CephFSVolumeSource": { + "id": "v1.CephFSVolumeSource", + "description": "Represents a Ceph Filesystem mount that lasts the lifetime of a pod Cephfs volumes do not support ownership management or SELinux relabeling.", + "required": [ + "monitors" + ], + "properties": { + "monitors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Required: Monitors is a collection of Ceph monitors More info: http://releases.k8s.io/HEAD/examples/cephfs/README.md#how-to-use-it" + }, + "path": { + "type": "string", + "description": "Optional: Used as the mounted root, rather than the full Ceph tree, default is /" + }, + "user": { + "type": "string", + "description": "Optional: User is the rados user name, default is admin More info: http://releases.k8s.io/HEAD/examples/cephfs/README.md#how-to-use-it" + }, + "secretFile": { + "type": "string", + "description": "Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: http://releases.k8s.io/HEAD/examples/cephfs/README.md#how-to-use-it" + }, + "secretRef": { + "$ref": "v1.LocalObjectReference", + "description": "Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: http://releases.k8s.io/HEAD/examples/cephfs/README.md#how-to-use-it" + }, + "readOnly": { + "type": "boolean", + "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: http://releases.k8s.io/HEAD/examples/cephfs/README.md#how-to-use-it" + } + } + }, + "v1.FlockerVolumeSource": { + "id": "v1.FlockerVolumeSource", + "description": "Represents a Flocker volume mounted by the Flocker agent. Flocker volumes do not support ownership management or SELinux relabeling.", + "required": [ + "datasetName" + ], + "properties": { + "datasetName": { + "type": "string", + "description": "Required: the volume name. This is going to be store on metadata -\u003e name on the payload for Flocker" + } + } + }, + "v1.DownwardAPIVolumeSource": { + "id": "v1.DownwardAPIVolumeSource", + "description": "DownwardAPIVolumeSource represents a volume containing downward API info. Downward API volumes support ownership management and SELinux relabeling.", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "v1.DownwardAPIVolumeFile" + }, + "description": "Items is a list of downward API volume file" + } + } + }, + "v1.DownwardAPIVolumeFile": { + "id": "v1.DownwardAPIVolumeFile", + "description": "DownwardAPIVolumeFile represents information to create the file containing the pod field", + "required": [ + "path", + "fieldRef" + ], + "properties": { + "path": { + "type": "string", + "description": "Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'" + }, + "fieldRef": { + "$ref": "v1.ObjectFieldSelector", + "description": "Required: Selects a field of the pod: only annotations, labels, name and namespace are supported." + } + } + }, + "v1.ObjectFieldSelector": { + "id": "v1.ObjectFieldSelector", + "description": "ObjectFieldSelector selects an APIVersioned field of an object.", + "required": [ + "fieldPath" + ], + "properties": { + "apiVersion": { + "type": "string", + "description": "Version of the schema the FieldPath is written in terms of, defaults to \"v1\"." + }, + "fieldPath": { + "type": "string", + "description": "Path of the field to select in the specified API version." + } + } + }, + "v1.FCVolumeSource": { + "id": "v1.FCVolumeSource", + "description": "Represents a Fibre Channel volume. Fibre Channel volumes can only be mounted as read/write once. Fibre Channel volumes support ownership management and SELinux relabeling.", + "required": [ + "targetWWNs", + "lun" + ], + "properties": { + "targetWWNs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Required: FC target world wide names (WWNs)" + }, + "lun": { + "type": "integer", + "format": "int32", + "description": "Required: FC target lun number" + }, + "fsType": { + "type": "string", + "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified." + }, + "readOnly": { + "type": "boolean", + "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts." + } + } + }, + "v1.AzureFileVolumeSource": { + "id": "v1.AzureFileVolumeSource", + "description": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.", + "required": [ + "secretName", + "shareName" + ], + "properties": { + "secretName": { + "type": "string", + "description": "the name of secret that contains Azure Storage Account Name and Key" + }, + "shareName": { + "type": "string", + "description": "Share Name" + }, + "readOnly": { + "type": "boolean", + "description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts." + } + } + }, + "v1.ConfigMapVolumeSource": { + "id": "v1.ConfigMapVolumeSource", + "description": "Adapts a ConfigMap into a volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. ConfigMap volumes support ownership management and SELinux relabeling.", + "properties": { + "name": { + "type": "string", + "description": "Name of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names" + }, + "items": { + "type": "array", + "items": { + "$ref": "v1.KeyToPath" + }, + "description": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error. Paths must be relative and may not contain the '..' path or start with '..'." + } + } + }, + "v1.KeyToPath": { + "id": "v1.KeyToPath", + "description": "Maps a string key to a path within a volume.", + "required": [ + "key", + "path" + ], + "properties": { + "key": { + "type": "string", + "description": "The key to project." + }, + "path": { + "type": "string", + "description": "The relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'." + } + } + }, + "v1.Container": { + "id": "v1.Container", + "description": "A single application container that you want to run within a pod.", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique name (DNS_LABEL). Cannot be updated." + }, + "image": { + "type": "string", + "description": "Docker image name. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md" + }, + "command": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/containers.md#containers-and-commands" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/containers.md#containers-and-commands" + }, + "workingDir": { + "type": "string", + "description": "Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated." + }, + "ports": { + "type": "array", + "items": { + "$ref": "v1.ContainerPort" + }, + "description": "List of ports to expose from the container. Exposing a port here gives the system additional information about the network connections a container uses, but is primarily informational. Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default \"0.0.0.0\" address inside a container will be accessible from the network. Cannot be updated." + }, + "env": { + "type": "array", + "items": { + "$ref": "v1.EnvVar" + }, + "description": "List of environment variables to set in the container. Cannot be updated." + }, + "resources": { + "$ref": "v1.ResourceRequirements", + "description": "Compute Resources required by this container. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#resources" + }, + "volumeMounts": { + "type": "array", + "items": { + "$ref": "v1.VolumeMount" + }, + "description": "Pod volumes to mount into the container's filesyste. Cannot be updated." + }, + "livenessProbe": { + "$ref": "v1.Probe", + "description": "Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-probes" + }, + "readinessProbe": { + "$ref": "v1.Probe", + "description": "Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-probes" + }, + "lifecycle": { + "$ref": "v1.Lifecycle", + "description": "Actions that the management system should take in response to container lifecycle events. Cannot be updated." + }, + "terminationMessagePath": { + "type": "string", + "description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated." + }, + "imagePullPolicy": { + "type": "string", + "description": "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md#updating-images" + }, + "securityContext": { + "$ref": "v1.SecurityContext", + "description": "Security options the pod should run with. More info: http://releases.k8s.io/HEAD/docs/design/security_context.md" + }, + "stdin": { + "type": "boolean", + "description": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false." + }, + "stdinOnce": { + "type": "boolean", + "description": "Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false" + }, + "tty": { + "type": "boolean", + "description": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false." + } + } + }, + "v1.ContainerPort": { + "id": "v1.ContainerPort", + "description": "ContainerPort represents a network port in a single container.", + "required": [ + "containerPort" + ], + "properties": { + "name": { + "type": "string", + "description": "If specified, this must be an IANA_SVC_NAME and unique within the pod. Each named port in a pod must have a unique name. Name for the port that can be referred to by services." + }, + "hostPort": { + "type": "integer", + "format": "int32", + "description": "Number of port to expose on the host. If specified, this must be a valid port number, 0 \u003c x \u003c 65536. If HostNetwork is specified, this must match ContainerPort. Most containers do not need this." + }, + "containerPort": { + "type": "integer", + "format": "int32", + "description": "Number of port to expose on the pod's IP address. This must be a valid port number, 0 \u003c x \u003c 65536." + }, + "protocol": { + "type": "string", + "description": "Protocol for port. Must be UDP or TCP. Defaults to \"TCP\"." + }, + "hostIP": { + "type": "string", + "description": "What host IP to bind the external port to." + } + } + }, + "v1.EnvVar": { + "id": "v1.EnvVar", + "description": "EnvVar represents an environment variable present in a Container.", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the environment variable. Must be a C_IDENTIFIER." + }, + "value": { + "type": "string", + "description": "Variable references $(VAR_NAME) are expanded using the previous defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to \"\"." + }, + "valueFrom": { + "$ref": "v1.EnvVarSource", + "description": "Source for the environment variable's value. Cannot be used if value is not empty." + } + } + }, + "v1.EnvVarSource": { + "id": "v1.EnvVarSource", + "description": "EnvVarSource represents a source for the value of an EnvVar.", + "properties": { + "fieldRef": { + "$ref": "v1.ObjectFieldSelector", + "description": "Selects a field of the pod; only name and namespace are supported." + }, + "configMapKeyRef": { + "$ref": "v1.ConfigMapKeySelector", + "description": "Selects a key of a ConfigMap." + }, + "secretKeyRef": { + "$ref": "v1.SecretKeySelector", + "description": "Selects a key of a secret in the pod's namespace" + } + } + }, + "v1.ConfigMapKeySelector": { + "id": "v1.ConfigMapKeySelector", + "description": "Selects a key from a ConfigMap.", + "required": [ + "key" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names" + }, + "key": { + "type": "string", + "description": "The key to select." + } + } + }, + "v1.SecretKeySelector": { + "id": "v1.SecretKeySelector", + "description": "SecretKeySelector selects a key of a Secret.", + "required": [ + "key" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names" + }, + "key": { + "type": "string", + "description": "The key of the secret to select from. Must be a valid secret key." + } + } + }, + "v1.ResourceRequirements": { + "id": "v1.ResourceRequirements", + "description": "ResourceRequirements describes the compute resource requirements.", + "properties": { + "limits": { + "type": "object", + "description": "Limits describes the maximum amount of compute resources allowed. More info: http://releases.k8s.io/HEAD/docs/design/resources.md#resource-specifications" + }, + "requests": { + "type": "object", + "description": "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: http://releases.k8s.io/HEAD/docs/design/resources.md#resource-specifications" + } + } + }, + "v1.VolumeMount": { + "id": "v1.VolumeMount", + "description": "VolumeMount describes a mounting of a Volume within a container.", + "required": [ + "name", + "mountPath" + ], + "properties": { + "name": { + "type": "string", + "description": "This must match the Name of a Volume." + }, + "readOnly": { + "type": "boolean", + "description": "Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false." + }, + "mountPath": { + "type": "string", + "description": "Path within the container at which the volume should be mounted. Must not contain ':'." + } + } + }, + "v1.Probe": { + "id": "v1.Probe", + "description": "Probe describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic.", + "properties": { + "exec": { + "$ref": "v1.ExecAction", + "description": "One and only one of the following should be specified. Exec specifies the action to take." + }, + "httpGet": { + "$ref": "v1.HTTPGetAction", + "description": "HTTPGet specifies the http request to perform." + }, + "tcpSocket": { + "$ref": "v1.TCPSocketAction", + "description": "TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported" + }, + "initialDelaySeconds": { + "type": "integer", + "format": "int32", + "description": "Number of seconds after the container has started before liveness probes are initiated. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-probes" + }, + "timeoutSeconds": { + "type": "integer", + "format": "int32", + "description": "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-probes" + }, + "periodSeconds": { + "type": "integer", + "format": "int32", + "description": "How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1." + }, + "successThreshold": { + "type": "integer", + "format": "int32", + "description": "Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness. Minimum value is 1." + }, + "failureThreshold": { + "type": "integer", + "format": "int32", + "description": "Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1." + } + } + }, + "v1.ExecAction": { + "id": "v1.ExecAction", + "description": "ExecAction describes a \"run in container\" action.", + "properties": { + "command": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy." + } + } + }, + "v1.HTTPGetAction": { + "id": "v1.HTTPGetAction", + "description": "HTTPGetAction describes an action based on HTTP Get requests.", + "required": [ + "port" + ], + "properties": { + "path": { + "type": "string", + "description": "Path to access on the HTTP server." + }, + "port": { + "type": "string", + "description": "Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME." + }, + "host": { + "type": "string", + "description": "Host name to connect to, defaults to the pod IP. You probably want to set \"Host\" in httpHeaders instead." + }, + "scheme": { + "type": "string", + "description": "Scheme to use for connecting to the host. Defaults to HTTP." + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "v1.HTTPHeader" + }, + "description": "Custom headers to set in the request. HTTP allows repeated headers." + } + } + }, + "v1.HTTPHeader": { + "id": "v1.HTTPHeader", + "description": "HTTPHeader describes a custom header to be used in HTTP probes", + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string", + "description": "The header field name" + }, + "value": { + "type": "string", + "description": "The header field value" + } + } + }, + "v1.TCPSocketAction": { + "id": "v1.TCPSocketAction", + "description": "TCPSocketAction describes an action based on opening a socket", + "required": [ + "port" + ], + "properties": { + "port": { + "type": "string", + "description": "Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME." + } + } + }, + "v1.Lifecycle": { + "id": "v1.Lifecycle", + "description": "Lifecycle describes actions that the management system should take in response to container lifecycle events. For the PostStart and PreStop lifecycle handlers, management of the container blocks until the action is complete, unless the container process fails, in which case the handler is aborted.", + "properties": { + "postStart": { + "$ref": "v1.Handler", + "description": "PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: http://releases.k8s.io/HEAD/docs/user-guide/container-environment.md#hook-details" + }, + "preStop": { + "$ref": "v1.Handler", + "description": "PreStop is called immediately before a container is terminated. The container is terminated after the handler completes. The reason for termination is passed to the handler. Regardless of the outcome of the handler, the container is eventually terminated. Other management of the container blocks until the hook completes. More info: http://releases.k8s.io/HEAD/docs/user-guide/container-environment.md#hook-details" + } + } + }, + "v1.Handler": { + "id": "v1.Handler", + "description": "Handler defines a specific action that should be taken", + "properties": { + "exec": { + "$ref": "v1.ExecAction", + "description": "One and only one of the following should be specified. Exec specifies the action to take." + }, + "httpGet": { + "$ref": "v1.HTTPGetAction", + "description": "HTTPGet specifies the http request to perform." + }, + "tcpSocket": { + "$ref": "v1.TCPSocketAction", + "description": "TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported" + } + } + }, + "v1.SecurityContext": { + "id": "v1.SecurityContext", + "description": "SecurityContext holds security configuration that will be applied to a container. Some fields are present in both SecurityContext and PodSecurityContext. When both are set, the values in SecurityContext take precedence.", + "properties": { + "capabilities": { + "$ref": "v1.Capabilities", + "description": "The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime." + }, + "privileged": { + "type": "boolean", + "description": "Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false." + }, + "seLinuxOptions": { + "$ref": "v1.SELinuxOptions", + "description": "The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence." + }, + "runAsUser": { + "type": "integer", + "format": "int64", + "description": "The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence." + }, + "runAsNonRoot": { + "type": "boolean", + "description": "Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence." + }, + "readOnlyRootFilesystem": { + "type": "boolean", + "description": "Whether this container has a read-only root filesystem. Default is false." + } + } + }, + "v1.Capabilities": { + "id": "v1.Capabilities", + "description": "Adds and removes POSIX capabilities from running containers.", + "properties": { + "add": { + "type": "array", + "items": { + "$ref": "v1.Capability" + }, + "description": "Added capabilities" + }, + "drop": { + "type": "array", + "items": { + "$ref": "v1.Capability" + }, + "description": "Removed capabilities" + } + } + }, + "v1.Capability": { + "id": "v1.Capability", + "properties": {} + }, + "v1.SELinuxOptions": { + "id": "v1.SELinuxOptions", + "description": "SELinuxOptions are the labels to be applied to the container", + "properties": { + "user": { + "type": "string", + "description": "User is a SELinux user label that applies to the container." + }, + "role": { + "type": "string", + "description": "Role is a SELinux role label that applies to the container." + }, + "type": { + "type": "string", + "description": "Type is a SELinux type label that applies to the container." + }, + "level": { + "type": "string", + "description": "Level is SELinux level label that applies to the container." + } + } + }, + "v1.PodSecurityContext": { + "id": "v1.PodSecurityContext", + "description": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.", + "properties": { + "seLinuxOptions": { + "$ref": "v1.SELinuxOptions", + "description": "The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container." + }, + "runAsUser": { + "type": "integer", + "format": "int64", + "description": "The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container." + }, + "runAsNonRoot": { + "type": "boolean", + "description": "Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence." + }, + "supplementalGroups": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container." + }, + "fsGroup": { + "type": "integer", + "format": "int64", + "description": "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw " + } + } + }, + "v1.PersistentVolumeClaim": { + "id": "v1.PersistentVolumeClaim", + "description": "PersistentVolumeClaim is a user's request for and claim to a persistent volume", + "properties": { + "kind": { + "type": "string", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + }, + "apiVersion": { + "type": "string", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources" + }, + "metadata": { + "$ref": "v1.ObjectMeta", + "description": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata" + }, + "spec": { + "$ref": "v1.PersistentVolumeClaimSpec", + "description": "Spec defines the desired characteristics of a volume requested by a pod author. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistentvolumeclaims" + }, + "status": { + "$ref": "v1.PersistentVolumeClaimStatus", + "description": "Status represents the current information/status of a persistent volume claim. Read-only. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistentvolumeclaims" + } + } + }, + "v1.PersistentVolumeClaimSpec": { + "id": "v1.PersistentVolumeClaimSpec", + "description": "PersistentVolumeClaimSpec describes the common attributes of storage devices and allows a Source for provider-specific attributes", + "properties": { + "accessModes": { + "type": "array", + "items": { + "$ref": "v1.PersistentVolumeAccessMode" + }, + "description": "AccessModes contains the desired access modes the volume should have. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#access-modes-1" + }, + "resources": { + "$ref": "v1.ResourceRequirements", + "description": "Resources represents the minimum resources the volume should have. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#resources" + }, + "volumeName": { + "type": "string", + "description": "VolumeName is the binding reference to the PersistentVolume backing this claim." + } + } + }, + "v1.PersistentVolumeAccessMode": { + "id": "v1.PersistentVolumeAccessMode", + "properties": {} + }, + "v1.PersistentVolumeClaimStatus": { + "id": "v1.PersistentVolumeClaimStatus", + "description": "PersistentVolumeClaimStatus is the current status of a persistent volume claim.", + "properties": { + "phase": { + "type": "string", + "description": "Phase represents the current phase of PersistentVolumeClaim." + }, + "accessModes": { + "type": "array", + "items": { + "$ref": "v1.PersistentVolumeAccessMode" + }, + "description": "AccessModes contains the actual access modes the volume backing the PVC has. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#access-modes-1" + }, + "capacity": { + "type": "object", + "description": "Represents the actual resources of the underlying volume." + } + } + }, + "v1alpha1.PetSetStatus": { + "id": "v1alpha1.PetSetStatus", + "description": "PetSetStatus represents the current state of a PetSet.", + "required": [ + "replicas" + ], + "properties": { + "observedGeneration": { + "type": "integer", + "format": "int64", + "description": "most recent generation observed by this autoscaler." + }, + "replicas": { + "type": "integer", + "format": "int32", + "description": "Replicas is the number of actual replicas." + } + } + }, + "unversioned.Status": { + "id": "unversioned.Status", + "description": "Status is a return value for calls that don't return other objects.", + "properties": { + "kind": { + "type": "string", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + }, + "apiVersion": { + "type": "string", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources" + }, + "metadata": { + "$ref": "unversioned.ListMeta", + "description": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + }, + "status": { + "type": "string", + "description": "Status of the operation. One of: \"Success\" or \"Failure\". More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status" + }, + "message": { + "type": "string", + "description": "A human-readable description of the status of this operation." + }, + "reason": { + "type": "string", + "description": "A machine-readable description of why this operation is in the \"Failure\" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it." + }, + "details": { + "$ref": "unversioned.StatusDetails", + "description": "Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type." + }, + "code": { + "type": "integer", + "format": "int32", + "description": "Suggested HTTP return code for this status, 0 if not set." + } + } + }, + "unversioned.StatusDetails": { + "id": "unversioned.StatusDetails", + "description": "StatusDetails is a set of additional properties that MAY be set by the server to provide additional information about a response. The Reason field of a Status object defines what attributes will be set. Clients must ignore fields that do not match the defined type of each attribute, and should assume that any attribute may be empty, invalid, or under defined.", + "properties": { + "name": { + "type": "string", + "description": "The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described)." + }, + "group": { + "type": "string", + "description": "The group attribute of the resource associated with the status StatusReason." + }, + "kind": { + "type": "string", + "description": "The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + }, + "causes": { + "type": "array", + "items": { + "$ref": "unversioned.StatusCause" + }, + "description": "The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes." + }, + "retryAfterSeconds": { + "type": "integer", + "format": "int32", + "description": "If specified, the time in seconds before the operation should be retried." + } + } + }, + "unversioned.StatusCause": { + "id": "unversioned.StatusCause", + "description": "StatusCause provides more information about an api.Status failure, including cases when multiple errors are encountered.", + "properties": { + "reason": { + "type": "string", + "description": "A machine-readable description of the cause of the error. If this value is empty there is no information available." + }, + "message": { + "type": "string", + "description": "A human-readable description of the cause of the error. This field may be presented as-is to a reader." + }, + "field": { + "type": "string", + "description": "The field of the resource that has caused this error, as named by its JSON serialization. May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional.\n\nExamples:\n \"name\" - the field \"name\" on the current resource\n \"items[0].name\" - the field \"name\" on the first array entry in \"items\"" + } + } + }, + "*versioned.Event": { + "id": "*versioned.Event", + "properties": {} + }, + "unversioned.Patch": { + "id": "unversioned.Patch", + "description": "Patch is provided to give a concrete name and type to the Kubernetes PATCH request body.", + "properties": {} + }, + "v1.DeleteOptions": { + "id": "v1.DeleteOptions", + "description": "DeleteOptions may be provided when deleting an API object", + "properties": { + "kind": { + "type": "string", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + }, + "apiVersion": { + "type": "string", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources" + }, + "gracePeriodSeconds": { + "type": "integer", + "format": "int64", + "description": "The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately." + }, + "preconditions": { + "$ref": "v1.Preconditions", + "description": "Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be returned." + } + } + }, + "v1.Preconditions": { + "id": "v1.Preconditions", + "description": "Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out.", + "properties": { + "uid": { + "$ref": "types.UID", + "description": "Specifies the target UID." + } + } + }, + "types.UID": { + "id": "types.UID", + "properties": {} + }, + "unversioned.APIResourceList": { + "id": "unversioned.APIResourceList", + "description": "APIResourceList is a list of APIResource, it is used to expose the name of the resources supported in a specific group and version, and if the resource is namespaced.", + "required": [ + "groupVersion", + "resources" + ], + "properties": { + "kind": { + "type": "string", + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + }, + "apiVersion": { + "type": "string", + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources" + }, + "groupVersion": { + "type": "string", + "description": "groupVersion is the group and version this APIResourceList is for." + }, + "resources": { + "type": "array", + "items": { + "$ref": "unversioned.APIResource" + }, + "description": "resources contains the name of the resources and if they are namespaced." + } + } + }, + "unversioned.APIResource": { + "id": "unversioned.APIResource", + "description": "APIResource specifies the name of a resource and whether it is namespaced.", + "required": [ + "name", + "namespaced", + "kind" + ], + "properties": { + "name": { + "type": "string", + "description": "name is the name of the resource." + }, + "namespaced": { + "type": "boolean", + "description": "namespaced indicates if a resource is namespaced or not." + }, + "kind": { + "type": "string", + "description": "kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo')" + } + } + } + } + } diff --git a/api/swagger-spec/resourceListing.json b/api/swagger-spec/resourceListing.json index f58f7240f0d..45924c731e6 100644 --- a/api/swagger-spec/resourceListing.json +++ b/api/swagger-spec/resourceListing.json @@ -40,6 +40,14 @@ { "path": "/apis/batch", "description": "get information of a group" + }, + { + "path": "/apis/apps/v1alpha1", + "description": "API at /apis/apps/v1alpha1" + }, + { + "path": "/apis/apps", + "description": "get information of a group" } ], "apiVersion": "", diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 72e1f71e4cd..2a76048b729 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -38,6 +38,8 @@ import ( "k8s.io/kubernetes/pkg/api/unversioned" apiv1 "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/apps" + appsapi "k8s.io/kubernetes/pkg/apis/apps/v1alpha1" "k8s.io/kubernetes/pkg/apis/autoscaling" autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1" "k8s.io/kubernetes/pkg/apis/batch" @@ -346,6 +348,29 @@ func Run(s *options.APIServer) error { storageDestinations.AddAPIGroup(batch.GroupName, batchEtcdStorage) } + if apiResourceConfigSource.AnyResourcesForVersionEnabled(appsapi.SchemeGroupVersion) { + glog.Infof("Configuring apps/v1alpha1 storage destination") + appsGroup, err := registered.Group(apps.GroupName) + if err != nil { + glog.Fatalf("Apps API is enabled in runtime config, but not enabled in the environment variable KUBE_API_VERSIONS. Error: %v", err) + } + // Figure out what storage group/version we should use. + storageGroupVersion, found := storageVersions[appsGroup.GroupVersion.Group] + if !found { + glog.Fatalf("Couldn't find the storage version for group: %q in storageVersions: %v", appsGroup.GroupVersion.Group, storageVersions) + } + + if storageGroupVersion != "apps/v1alpha1" { + glog.Fatalf("The storage version for apps must be apps/v1alpha1") + } + glog.Infof("Using %v for petset group storage version", storageGroupVersion) + appsEtcdStorage, err := newEtcd(api.Codecs, storageGroupVersion, "apps/__internal", s.EtcdConfig) + if err != nil { + glog.Fatalf("Invalid extensions storage version or misconfigured etcd: %v", err) + } + storageDestinations.AddAPIGroup(apps.GroupName, appsEtcdStorage) + } + updateEtcdOverrides(s.EtcdServersOverrides, storageVersions, s.EtcdConfig, &storageDestinations, newEtcd) // Default to the private server key for service account token signing @@ -477,6 +502,7 @@ func parseRuntimeConfig(s *options.APIServer) (genericapiserver.APIResourceConfi extensionsapiv1beta1.SchemeGroupVersion: extensionsGroupVersionString, batchapiv1.SchemeGroupVersion: batchapiv1.SchemeGroupVersion.String(), autoscalingapiv1.SchemeGroupVersion: autoscalingapiv1.SchemeGroupVersion.String(), + appsapi.SchemeGroupVersion: appsapi.SchemeGroupVersion.String(), } resourceConfig := master.DefaultAPIResourceConfigSource() diff --git a/cmd/libs/go2idl/conversion-gen/main.go b/cmd/libs/go2idl/conversion-gen/main.go index 907283f5cc1..2fd09ac57b4 100644 --- a/cmd/libs/go2idl/conversion-gen/main.go +++ b/cmd/libs/go2idl/conversion-gen/main.go @@ -41,6 +41,8 @@ func main() { "k8s.io/kubernetes/pkg/apis/autoscaling/v1", "k8s.io/kubernetes/pkg/apis/batch", "k8s.io/kubernetes/pkg/apis/batch/v1", + "k8s.io/kubernetes/pkg/apis/apps", + "k8s.io/kubernetes/pkg/apis/apps/v1alpha1", "k8s.io/kubernetes/pkg/apis/componentconfig", "k8s.io/kubernetes/pkg/apis/componentconfig/v1alpha1", "k8s.io/kubernetes/pkg/apis/extensions", diff --git a/cmd/libs/go2idl/deepcopy-gen/main.go b/cmd/libs/go2idl/deepcopy-gen/main.go index aed1a06d740..0e0a174f7c9 100644 --- a/cmd/libs/go2idl/deepcopy-gen/main.go +++ b/cmd/libs/go2idl/deepcopy-gen/main.go @@ -41,6 +41,8 @@ func main() { "k8s.io/kubernetes/pkg/apis/autoscaling/v1", "k8s.io/kubernetes/pkg/apis/batch", "k8s.io/kubernetes/pkg/apis/batch/v1", + "k8s.io/kubernetes/pkg/apis/apps", + "k8s.io/kubernetes/pkg/apis/apps/v1alpha1", "k8s.io/kubernetes/pkg/apis/componentconfig", "k8s.io/kubernetes/pkg/apis/componentconfig/v1alpha1", "k8s.io/kubernetes/pkg/apis/extensions", diff --git a/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go b/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go index 47e26d7d683..d1e8d32f44e 100644 --- a/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go +++ b/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go @@ -69,6 +69,7 @@ func New() *Generator { `k8s.io/kubernetes/pkg/apis/extensions/v1beta1`, `k8s.io/kubernetes/pkg/apis/autoscaling/v1`, `k8s.io/kubernetes/pkg/apis/batch/v1`, + `k8s.io/kubernetes/pkg/apis/apps/v1alpha1`, }, ","), DropEmbeddedFields: "k8s.io/kubernetes/pkg/api/unversioned.TypeMeta", } diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index 6afd503a584..3125cd294ec 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -421,6 +421,7 @@ _kubectl_get() must_have_one_noun+=("node") must_have_one_noun+=("persistentvolume") must_have_one_noun+=("persistentvolumeclaim") + must_have_one_noun+=("petset") must_have_one_noun+=("pod") must_have_one_noun+=("podsecuritypolicy") must_have_one_noun+=("podtemplate") @@ -456,6 +457,7 @@ _kubectl_get() noun_aliases+=("ns") noun_aliases+=("persistentvolumeclaims") noun_aliases+=("persistentvolumes") + noun_aliases+=("petsets") noun_aliases+=("po") noun_aliases+=("pods") noun_aliases+=("podsecuritypolicies") @@ -1170,6 +1172,7 @@ _kubectl_patch() must_have_one_noun+=("node") must_have_one_noun+=("persistentvolume") must_have_one_noun+=("persistentvolumeclaim") + must_have_one_noun+=("petset") must_have_one_noun+=("pod") must_have_one_noun+=("podsecuritypolicy") must_have_one_noun+=("podtemplate") @@ -1205,6 +1208,7 @@ _kubectl_patch() noun_aliases+=("ns") noun_aliases+=("persistentvolumeclaims") noun_aliases+=("persistentvolumes") + noun_aliases+=("petsets") noun_aliases+=("po") noun_aliases+=("pods") noun_aliases+=("podsecuritypolicies") @@ -1299,6 +1303,7 @@ _kubectl_delete() must_have_one_noun+=("node") must_have_one_noun+=("persistentvolume") must_have_one_noun+=("persistentvolumeclaim") + must_have_one_noun+=("petset") must_have_one_noun+=("pod") must_have_one_noun+=("podsecuritypolicy") must_have_one_noun+=("podtemplate") @@ -1334,6 +1339,7 @@ _kubectl_delete() noun_aliases+=("ns") noun_aliases+=("persistentvolumeclaims") noun_aliases+=("persistentvolumes") + noun_aliases+=("petsets") noun_aliases+=("po") noun_aliases+=("pods") noun_aliases+=("podsecuritypolicies") @@ -1424,6 +1430,7 @@ _kubectl_edit() must_have_one_noun+=("node") must_have_one_noun+=("persistentvolume") must_have_one_noun+=("persistentvolumeclaim") + must_have_one_noun+=("petset") must_have_one_noun+=("pod") must_have_one_noun+=("podsecuritypolicy") must_have_one_noun+=("podtemplate") @@ -1459,6 +1466,7 @@ _kubectl_edit() noun_aliases+=("ns") noun_aliases+=("persistentvolumeclaims") noun_aliases+=("persistentvolumes") + noun_aliases+=("petsets") noun_aliases+=("po") noun_aliases+=("pods") noun_aliases+=("podsecuritypolicies") @@ -2708,6 +2716,7 @@ _kubectl_label() must_have_one_noun+=("node") must_have_one_noun+=("persistentvolume") must_have_one_noun+=("persistentvolumeclaim") + must_have_one_noun+=("petset") must_have_one_noun+=("pod") must_have_one_noun+=("podsecuritypolicy") must_have_one_noun+=("podtemplate") @@ -2743,6 +2752,7 @@ _kubectl_label() noun_aliases+=("ns") noun_aliases+=("persistentvolumeclaims") noun_aliases+=("persistentvolumes") + noun_aliases+=("petsets") noun_aliases+=("po") noun_aliases+=("pods") noun_aliases+=("podsecuritypolicies") diff --git a/docs/admin/kube-apiserver.md b/docs/admin/kube-apiserver.md index ca975310f4c..71c5c6c60a4 100644 --- a/docs/admin/kube-apiserver.md +++ b/docs/admin/kube-apiserver.md @@ -109,7 +109,7 @@ kube-apiserver --service-node-port-range=: A port range to reserve for services with NodePort visibility. Example: '30000-32767'. Inclusive at both ends of the range. --ssh-keyfile="": If non-empty, use secure SSH proxy to the nodes, using this user keyfile --ssh-user="": If non-empty, use secure SSH proxy to the nodes, using this user name - --storage-versions="authorization.k8s.io/v1beta1,autoscaling/v1,batch/v1,componentconfig/v1alpha1,extensions/v1beta1,metrics/v1alpha1,v1": The per-group version to store resources in. Specified in the format "group1/version1,group2/version2,...". In the case where objects are moved from one group to the other, you may specify the format "group1=group2/v1beta1,group3/v1beta1,...". You only need to pass the groups you wish to change from the defaults. It defaults to a list of preferred versions of all registered groups, which is derived from the KUBE_API_VERSIONS environment variable. + --storage-versions="apps/v1alpha1,authorization.k8s.io/v1beta1,autoscaling/v1,batch/v1,componentconfig/v1alpha1,extensions/v1beta1,metrics/v1alpha1,v1": The per-group version to store resources in. Specified in the format "group1/version1,group2/version2,...". In the case where objects are moved from one group to the other, you may specify the format "group1=group2/v1beta1,group3/v1beta1,...". You only need to pass the groups you wish to change from the defaults. It defaults to a list of preferred versions of all registered groups, which is derived from the KUBE_API_VERSIONS environment variable. --tls-cert-file="": File containing x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert). If HTTPS serving is enabled, and --tls-cert-file and --tls-private-key-file are not provided, a self-signed certificate and key are generated for the public address and saved to /var/run/kubernetes. --tls-private-key-file="": File containing x509 private key matching --tls-cert-file. --token-auth-file="": If set, the file that will be used to secure the secure port of the API server via token authentication. @@ -117,7 +117,7 @@ kube-apiserver --watch-cache-sizes=[]: List of watch cache sizes for every resource (pods, nodes, etc.), comma separated. The individual override format: resource#size, where size is a number. It takes effect when watch-cache is enabled. ``` -###### Auto generated by spf13/cobra on 12-Apr-2016 +###### Auto generated by spf13/cobra on 16-Apr-2016 diff --git a/hack/after-build/update-swagger-spec.sh b/hack/after-build/update-swagger-spec.sh index 76a52e6e118..0648aefa1c6 100755 --- a/hack/after-build/update-swagger-spec.sh +++ b/hack/after-build/update-swagger-spec.sh @@ -66,7 +66,7 @@ APISERVER_PID=$! kube::util::wait_for_url "http://127.0.0.1:${API_PORT}/healthz" "apiserver: " SWAGGER_API_PATH="http://127.0.0.1:${API_PORT}/swaggerapi/" -DEFAULT_GROUP_VERSIONS="v1 autoscaling/v1 batch/v1 extensions/v1beta1" +DEFAULT_GROUP_VERSIONS="v1 autoscaling/v1 batch/v1 extensions/v1beta1 apps/v1alpha1" VERSIONS=${VERSIONS:-$DEFAULT_GROUP_VERSIONS} kube::log::status "Updating " ${SWAGGER_ROOT_DIR} diff --git a/hack/test-cmd.sh b/hack/test-cmd.sh index e6e7f7ce5be..3e93450367e 100755 --- a/hack/test-cmd.sh +++ b/hack/test-cmd.sh @@ -183,7 +183,7 @@ kube::log::status "Starting kube-apiserver" # Admission Controllers to invoke prior to persisting objects in cluster ADMISSION_CONTROL="NamespaceLifecycle,LimitRanger,ResourceQuota" -KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" "${KUBE_OUTPUT_HOSTBIN}/kube-apiserver" \ +KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1" "${KUBE_OUTPUT_HOSTBIN}/kube-apiserver" \ --address="127.0.0.1" \ --public-address-override="127.0.0.1" \ --port="${API_PORT}" \ @@ -529,7 +529,7 @@ runTests() { kubectl create -f hack/testdata/pod-with-precision.json "${kube_flags[@]}" # Post-condition: valid-pod POD is running kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'pod-with-precision:' - + ## Patch preserves precision # Command kubectl patch "${kube_flags[@]}" pod pod-with-precision -p='{"metadata":{"annotations":{"patchkey": "patchvalue"}}}' @@ -544,7 +544,7 @@ runTests() { # Post-condition: pod-with-precision POD has annotation kube::test::get_object_assert 'pod pod-with-precision' "{{${annotations_field}.annotatekey}}" 'annotatevalue' # Cleanup - kubectl delete pod pod-with-precision "${kube_flags[@]}" + kubectl delete pod pod-with-precision "${kube_flags[@]}" ### Create valid-pod POD # Pre-condition: no POD exists @@ -1792,6 +1792,6 @@ __EOF__ kube::test::clear_all } -KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" runTests "v1" +KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1" runTests "v1" kube::log::status "TEST PASSED" diff --git a/hack/test-go.sh b/hack/test-go.sh index 477db246cf5..a1d2d0da019 100755 --- a/hack/test-go.sh +++ b/hack/test-go.sh @@ -58,7 +58,7 @@ KUBE_GOVERALLS_BIN=${KUBE_GOVERALLS_BIN:-} # Lists of API Versions of each groups that should be tested, groups are # separated by comma, lists are separated by semicolon. e.g., # "v1,compute/v1alpha1,experimental/v1alpha2;v1,compute/v2,experimental/v1alpha3" -KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1,metrics/v1alpha1;v1,autoscaling/v1,batch/v1,extensions/v1beta1,metrics/v1alpha1"} +KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1,metrics/v1alpha1;v1,autoscaling/v1,batch/v1,extensions/v1beta1,apps/v1alpha1,metrics/v1alpha1"} # once we have multiple group supports # Run tests with the standard (registry) and a custom etcd prefix # (kubernetes.io/registry). @@ -326,7 +326,7 @@ for (( i=0, j=0; ; )); do # KUBE_TEST_API sets the version of each group to be tested. KUBE_API_VERSIONS # register the groups/versions as supported by k8s. So KUBE_API_VERSIONS # needs to be the superset of KUBE_TEST_API. - KUBE_TEST_API="${apiVersion}" KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1,componentconfig/v1alpha1,metrics/v1alpha1,authorization.k8s.io/v1beta1" ETCD_PREFIX=${etcdPrefix} runTests "$@" + KUBE_TEST_API="${apiVersion}" KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1,componentconfig/v1alpha1,metrics/v1alpha1,apps/v1alpha1,authorization.k8s.io/v1beta1" ETCD_PREFIX=${etcdPrefix} runTests "$@" i=${i}+1 j=${j}+1 if [[ i -eq ${apiVersionsCount} ]] && [[ j -eq ${etcdPrefixesCount} ]]; then diff --git a/hack/test-integration.sh b/hack/test-integration.sh index 3cd9fa351a9..02582b5eb5d 100755 --- a/hack/test-integration.sh +++ b/hack/test-integration.sh @@ -29,7 +29,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh" # "v1,compute/v1alpha1,experimental/v1alpha2;v1,compute/v2,experimental/v1alpha3" # TODO: It's going to be: # KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1"} -KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1;v1,autoscaling/v1,batch/v1,extensions/v1beta1"} +KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1;v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1"} # Give integration tests longer to run KUBE_TIMEOUT=${KUBE_TIMEOUT:--timeout 240s} @@ -52,11 +52,11 @@ runTests() { KUBE_RACE="" \ KUBE_TIMEOUT="${KUBE_TIMEOUT}" \ KUBE_TEST_API_VERSIONS="$1" \ - KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" \ + KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1" \ "${KUBE_ROOT}/hack/test-go.sh" test/integration kube::log::status "Running integration test scenario with watch cache on" - KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" KUBE_TEST_API_VERSIONS="$1" "${KUBE_OUTPUT_HOSTBIN}/integration" --v=${LOG_LEVEL} \ + KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1" KUBE_TEST_API_VERSIONS="$1" "${KUBE_OUTPUT_HOSTBIN}/integration" --v=${LOG_LEVEL} \ --max-concurrency="${KUBE_INTEGRATION_TEST_MAX_CONCURRENCY}" --watch-cache=true cleanup @@ -73,7 +73,7 @@ checkEtcdOnPath() { checkEtcdOnPath -KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" "${KUBE_ROOT}/hack/build-go.sh" "$@" cmd/integration +KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1" "${KUBE_ROOT}/hack/build-go.sh" "$@" cmd/integration # Run cleanup to stop etcd on interrupt or other kill signal. trap cleanup EXIT diff --git a/hack/update-api-reference-docs.sh b/hack/update-api-reference-docs.sh index 8ee47d7e221..027d28f374b 100755 --- a/hack/update-api-reference-docs.sh +++ b/hack/update-api-reference-docs.sh @@ -56,7 +56,7 @@ user_flags="-u $(id -u)" if [[ $(uname) == "Darwin" ]]; then # mapping in a uid from OS X doesn't make any sense user_flags="" -fi +fi for ver in $VERSIONS; do TMP_IN_HOST="${OUTPUT_TMP_IN_HOST}/${ver}" @@ -94,7 +94,7 @@ while read file; do generated=$(echo "${generated}" | grep -v "Last updated" || :) # By now, the contents should be normalized and stripped of any - # auto-managed content. + # auto-managed content. if diff -Bw >/dev/null <(echo "${original}") <(echo "${generated}"); then # actual contents same, overwrite generated with original. cp "${OUTPUT}/${file}" "${OUTPUT_TMP}/${file}" diff --git a/hack/update-generated-swagger-docs.sh b/hack/update-generated-swagger-docs.sh index 121870d345c..3d76e19b70d 100755 --- a/hack/update-generated-swagger-docs.sh +++ b/hack/update-generated-swagger-docs.sh @@ -56,7 +56,7 @@ EOF mv "$TMPFILE" "pkg/$(kube::util::group-version-to-pkg-path "${group_version}")/types_swagger_doc_generated.go" } -GROUP_VERSIONS=(unversioned v1 authorization/v1beta1 autoscaling/v1 batch/v1 extensions/v1beta1) +GROUP_VERSIONS=(unversioned v1 authorization/v1beta1 autoscaling/v1 batch/v1 extensions/v1beta1 apps/v1alpha1) # To avoid compile errors, remove the currently existing files. for group_version in "${GROUP_VERSIONS[@]}"; do rm -f "pkg/$(kube::util::group-version-to-pkg-path "${group_version}")/types_swagger_doc_generated.go" diff --git a/pkg/api/testapi/testapi.go b/pkg/api/testapi/testapi.go index 389c83ccad4..688cb33b98b 100644 --- a/pkg/api/testapi/testapi.go +++ b/pkg/api/testapi/testapi.go @@ -27,12 +27,14 @@ import ( "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/runtime" _ "k8s.io/kubernetes/pkg/api/install" + _ "k8s.io/kubernetes/pkg/apis/apps/install" _ "k8s.io/kubernetes/pkg/apis/autoscaling/install" _ "k8s.io/kubernetes/pkg/apis/batch/install" _ "k8s.io/kubernetes/pkg/apis/componentconfig/install" @@ -46,6 +48,7 @@ var ( Autoscaling TestGroup Batch TestGroup Extensions TestGroup + Apps TestGroup ) type TestGroup struct { @@ -122,10 +125,18 @@ func init() { internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion), } } + if _, ok := Groups[apps.GroupName]; !ok { + Groups[apps.GroupName] = TestGroup{ + externalGroupVersion: unversioned.GroupVersion{Group: apps.GroupName, Version: registered.GroupOrDie(apps.GroupName).GroupVersion.Version}, + internalGroupVersion: extensions.SchemeGroupVersion, + internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion), + } + } Default = Groups[api.GroupName] Autoscaling = Groups[autoscaling.GroupName] Batch = Groups[batch.GroupName] + Apps = Groups[apps.GroupName] Extensions = Groups[extensions.GroupName] } diff --git a/pkg/apis/apps/deep_copy_generated.go b/pkg/apis/apps/deep_copy_generated.go new file mode 100644 index 00000000000..5a2135c6a99 --- /dev/null +++ b/pkg/apis/apps/deep_copy_generated.go @@ -0,0 +1,117 @@ +// +build !ignore_autogenerated + +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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. +*/ + +// This file was autogenerated by deepcopy-gen. Do not edit it manually! + +package apps + +import ( + api "k8s.io/kubernetes/pkg/api" + unversioned "k8s.io/kubernetes/pkg/api/unversioned" + conversion "k8s.io/kubernetes/pkg/conversion" +) + +func init() { + if err := api.Scheme.AddGeneratedDeepCopyFuncs( + DeepCopy_apps_PetSet, + DeepCopy_apps_PetSetList, + DeepCopy_apps_PetSetSpec, + DeepCopy_apps_PetSetStatus, + ); err != nil { + // if one of the deep copy functions is malformed, detect it immediately. + panic(err) + } +} + +func DeepCopy_apps_PetSet(in PetSet, out *PetSet, c *conversion.Cloner) error { + if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil { + return err + } + if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil { + return err + } + if err := DeepCopy_apps_PetSetSpec(in.Spec, &out.Spec, c); err != nil { + return err + } + if err := DeepCopy_apps_PetSetStatus(in.Status, &out.Status, c); err != nil { + return err + } + return nil +} + +func DeepCopy_apps_PetSetList(in PetSetList, out *PetSetList, c *conversion.Cloner) error { + if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil { + return err + } + if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil { + return err + } + if in.Items != nil { + in, out := in.Items, &out.Items + *out = make([]PetSet, len(in)) + for i := range in { + if err := DeepCopy_apps_PetSet(in[i], &(*out)[i], c); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +func DeepCopy_apps_PetSetSpec(in PetSetSpec, out *PetSetSpec, c *conversion.Cloner) error { + out.Replicas = in.Replicas + if in.Selector != nil { + in, out := in.Selector, &out.Selector + *out = new(unversioned.LabelSelector) + if err := unversioned.DeepCopy_unversioned_LabelSelector(*in, *out, c); err != nil { + return err + } + } else { + out.Selector = nil + } + if err := api.DeepCopy_api_PodTemplateSpec(in.Template, &out.Template, c); err != nil { + return err + } + if in.VolumeClaimTemplates != nil { + in, out := in.VolumeClaimTemplates, &out.VolumeClaimTemplates + *out = make([]api.PersistentVolumeClaim, len(in)) + for i := range in { + if err := api.DeepCopy_api_PersistentVolumeClaim(in[i], &(*out)[i], c); err != nil { + return err + } + } + } else { + out.VolumeClaimTemplates = nil + } + out.ServiceName = in.ServiceName + return nil +} + +func DeepCopy_apps_PetSetStatus(in PetSetStatus, out *PetSetStatus, c *conversion.Cloner) error { + if in.ObservedGeneration != nil { + in, out := in.ObservedGeneration, &out.ObservedGeneration + *out = new(int64) + **out = *in + } else { + out.ObservedGeneration = nil + } + out.Replicas = in.Replicas + return nil +} diff --git a/pkg/apis/apps/install/install.go b/pkg/apis/apps/install/install.go new file mode 100644 index 00000000000..b4d9011d37f --- /dev/null +++ b/pkg/apis/apps/install/install.go @@ -0,0 +1,125 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 install installs the apps API group, making it available as +// an option to all of the API encoding/decoding machinery. +package install + +import ( + "fmt" + + "github.com/golang/glog" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/meta" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apimachinery" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/apis/apps/v1alpha1" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/util/sets" +) + +const importPrefix = "k8s.io/kubernetes/pkg/apis/apps" + +var accessor = meta.NewAccessor() + +// availableVersions lists all known external versions for this group from most preferred to least preferred +var availableVersions = []unversioned.GroupVersion{v1alpha1.SchemeGroupVersion} + +func init() { + registered.RegisterVersions(availableVersions) + externalVersions := []unversioned.GroupVersion{} + for _, v := range availableVersions { + if registered.IsAllowedVersion(v) { + externalVersions = append(externalVersions, v) + } + } + if len(externalVersions) == 0 { + glog.V(4).Infof("No version is registered for group %v", apps.GroupName) + return + } + + if err := registered.EnableVersions(externalVersions...); err != nil { + glog.V(4).Infof("%v", err) + return + } + if err := enableVersions(externalVersions); err != nil { + glog.V(4).Infof("%v", err) + return + } +} + +func enableVersions(externalVersions []unversioned.GroupVersion) error { + addVersionsToScheme(externalVersions...) + preferredExternalVersion := externalVersions[0] + + groupMeta := apimachinery.GroupMeta{ + GroupVersion: preferredExternalVersion, + GroupVersions: externalVersions, + RESTMapper: newRESTMapper(externalVersions), + SelfLinker: runtime.SelfLinker(accessor), + InterfacesFor: interfacesFor, + } + + if err := registered.RegisterGroup(groupMeta); err != nil { + return err + } + api.RegisterRESTMapper(groupMeta.RESTMapper) + return nil +} + +func newRESTMapper(externalVersions []unversioned.GroupVersion) meta.RESTMapper { + // the list of kinds that are scoped at the root of the api hierarchy + // if a kind is not enumerated here, it is assumed to have a namespace scope + rootScoped := sets.NewString() + + ignoredKinds := sets.NewString() + + return api.NewDefaultRESTMapper(externalVersions, interfacesFor, importPrefix, ignoredKinds, rootScoped) +} + +// interfacesFor returns the default Codec and ResourceVersioner for a given version +// string, or an error if the version is not known. +func interfacesFor(version unversioned.GroupVersion) (*meta.VersionInterfaces, error) { + switch version { + case v1alpha1.SchemeGroupVersion: + return &meta.VersionInterfaces{ + ObjectConvertor: api.Scheme, + MetadataAccessor: accessor, + }, nil + default: + g, _ := registered.Group(apps.GroupName) + return nil, fmt.Errorf("unsupported storage version: %s (valid: %v)", version, g.GroupVersions) + } +} + +func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) { + // add the internal version to Scheme + apps.AddToScheme(api.Scheme) + // add the enabled external versions to Scheme + for _, v := range externalVersions { + if !registered.IsEnabledVersion(v) { + glog.Errorf("Version %s is not enabled, so it will not be added to the Scheme.", v) + continue + } + switch v { + case v1alpha1.SchemeGroupVersion: + v1alpha1.AddToScheme(api.Scheme) + } + } +} diff --git a/pkg/apis/apps/register.go b/pkg/apis/apps/register.go new file mode 100644 index 00000000000..5192389bf27 --- /dev/null +++ b/pkg/apis/apps/register.go @@ -0,0 +1,57 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 apps + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/runtime" +) + +func AddToScheme(scheme *runtime.Scheme) { + // Add the API to Scheme. + addKnownTypes(scheme) +} + +// GroupName is the group name use in this package +const GroupName = "apps" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) unversioned.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns back a Group qualified GroupResource +func Resource(resource string) unversioned.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) { + // TODO this will get cleaned up with the scheme types are fixed + scheme.AddKnownTypes(SchemeGroupVersion, + &PetSet{}, + &PetSetList{}, + &api.ListOptions{}, + ) +} + +func (obj *PetSet) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *PetSetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } diff --git a/pkg/apis/apps/types.generated.go b/pkg/apis/apps/types.generated.go new file mode 100644 index 00000000000..a29c093d8e6 --- /dev/null +++ b/pkg/apis/apps/types.generated.go @@ -0,0 +1,1636 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +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. +*/ + +// ************************************************************ +// DO NOT EDIT. +// THIS FILE IS AUTO-GENERATED BY codecgen. +// ************************************************************ + +package apps + +import ( + "errors" + "fmt" + codec1978 "github.com/ugorji/go/codec" + pkg2_api "k8s.io/kubernetes/pkg/api" + pkg4_resource "k8s.io/kubernetes/pkg/api/resource" + pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned" + pkg3_types "k8s.io/kubernetes/pkg/types" + pkg6_intstr "k8s.io/kubernetes/pkg/util/intstr" + "reflect" + "runtime" + pkg5_inf "speter.net/go/exp/math/dec/inf" + time "time" +) + +const ( + // ----- content types ---- + codecSelferC_UTF81234 = 1 + codecSelferC_RAW1234 = 0 + // ----- value types used ---- + codecSelferValueTypeArray1234 = 10 + codecSelferValueTypeMap1234 = 9 + // ----- containerStateValues ---- + codecSelfer_containerMapKey1234 = 2 + codecSelfer_containerMapValue1234 = 3 + codecSelfer_containerMapEnd1234 = 4 + codecSelfer_containerArrayElem1234 = 6 + codecSelfer_containerArrayEnd1234 = 7 +) + +var ( + codecSelferBitsize1234 = uint8(reflect.TypeOf(uint(0)).Bits()) + codecSelferOnlyMapOrArrayEncodeToStructErr1234 = errors.New(`only encoded map or array can be decoded into a struct`) +) + +type codecSelfer1234 struct{} + +func init() { + if codec1978.GenVersion != 5 { + _, file, _, _ := runtime.Caller(0) + err := fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", + 5, codec1978.GenVersion, file) + panic(err) + } + if false { // reference the types, but skip this branch at build/run time + var v0 pkg2_api.ObjectMeta + var v1 pkg4_resource.Quantity + var v2 pkg1_unversioned.TypeMeta + var v3 pkg3_types.UID + var v4 pkg6_intstr.IntOrString + var v5 pkg5_inf.Dec + var v6 time.Time + _, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6 + } +} + +func (x *PetSet) CodecEncodeSelf(e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + if x == nil { + r.EncodeNil() + } else { + yym1 := z.EncBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.EncExt(x) { + } else { + yysep2 := !z.EncBinary() + yy2arr2 := z.EncBasicHandle().StructToArray + var yyq2 [5]bool + _, _, _ = yysep2, yyq2, yy2arr2 + const yyr2 bool = false + yyq2[0] = true + yyq2[1] = true + yyq2[2] = true + yyq2[3] = x.Kind != "" + yyq2[4] = x.APIVersion != "" + var yynn2 int + if yyr2 || yy2arr2 { + r.EncodeArrayStart(5) + } else { + yynn2 = 0 + for _, b := range yyq2 { + if b { + yynn2++ + } + } + r.EncodeMapStart(yynn2) + yynn2 = 0 + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[0] { + yy4 := &x.ObjectMeta + yy4.CodecEncodeSelf(e) + } else { + r.EncodeNil() + } + } else { + if yyq2[0] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("metadata")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yy6 := &x.ObjectMeta + yy6.CodecEncodeSelf(e) + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[1] { + yy9 := &x.Spec + yy9.CodecEncodeSelf(e) + } else { + r.EncodeNil() + } + } else { + if yyq2[1] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("spec")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yy11 := &x.Spec + yy11.CodecEncodeSelf(e) + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[2] { + yy14 := &x.Status + yy14.CodecEncodeSelf(e) + } else { + r.EncodeNil() + } + } else { + if yyq2[2] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("status")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yy16 := &x.Status + yy16.CodecEncodeSelf(e) + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[3] { + yym19 := z.EncBinary() + _ = yym19 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.Kind)) + } + } else { + r.EncodeString(codecSelferC_UTF81234, "") + } + } else { + if yyq2[3] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("kind")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym20 := z.EncBinary() + _ = yym20 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.Kind)) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[4] { + yym22 := z.EncBinary() + _ = yym22 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion)) + } + } else { + r.EncodeString(codecSelferC_UTF81234, "") + } + } else { + if yyq2[4] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("apiVersion")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym23 := z.EncBinary() + _ = yym23 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion)) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + z.EncSendContainerState(codecSelfer_containerMapEnd1234) + } + } + } +} + +func (x *PetSet) CodecDecodeSelf(d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + yym1 := z.DecBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.DecExt(x) { + } else { + yyct2 := r.ContainerType() + if yyct2 == codecSelferValueTypeMap1234 { + yyl2 := r.ReadMapStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerMapEnd1234) + } else { + x.codecDecodeSelfFromMap(yyl2, d) + } + } else if yyct2 == codecSelferValueTypeArray1234 { + yyl2 := r.ReadArrayStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + x.codecDecodeSelfFromArray(yyl2, d) + } + } else { + panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234) + } + } +} + +func (x *PetSet) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yys3Slc = z.DecScratchBuffer() // default slice to decode into + _ = yys3Slc + var yyhl3 bool = l >= 0 + for yyj3 := 0; ; yyj3++ { + if yyhl3 { + if yyj3 >= l { + break + } + } else { + if r.CheckBreak() { + break + } + } + z.DecSendContainerState(codecSelfer_containerMapKey1234) + yys3Slc = r.DecodeBytes(yys3Slc, true, true) + yys3 := string(yys3Slc) + z.DecSendContainerState(codecSelfer_containerMapValue1234) + switch yys3 { + case "metadata": + if r.TryDecodeAsNil() { + x.ObjectMeta = pkg2_api.ObjectMeta{} + } else { + yyv4 := &x.ObjectMeta + yyv4.CodecDecodeSelf(d) + } + case "spec": + if r.TryDecodeAsNil() { + x.Spec = PetSetSpec{} + } else { + yyv5 := &x.Spec + yyv5.CodecDecodeSelf(d) + } + case "status": + if r.TryDecodeAsNil() { + x.Status = PetSetStatus{} + } else { + yyv6 := &x.Status + yyv6.CodecDecodeSelf(d) + } + case "kind": + if r.TryDecodeAsNil() { + x.Kind = "" + } else { + x.Kind = string(r.DecodeString()) + } + case "apiVersion": + if r.TryDecodeAsNil() { + x.APIVersion = "" + } else { + x.APIVersion = string(r.DecodeString()) + } + default: + z.DecStructFieldNotFound(-1, yys3) + } // end switch yys3 + } // end for yyj3 + z.DecSendContainerState(codecSelfer_containerMapEnd1234) +} + +func (x *PetSet) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yyj9 int + var yyb9 bool + var yyhl9 bool = l >= 0 + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.ObjectMeta = pkg2_api.ObjectMeta{} + } else { + yyv10 := &x.ObjectMeta + yyv10.CodecDecodeSelf(d) + } + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Spec = PetSetSpec{} + } else { + yyv11 := &x.Spec + yyv11.CodecDecodeSelf(d) + } + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Status = PetSetStatus{} + } else { + yyv12 := &x.Status + yyv12.CodecDecodeSelf(d) + } + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Kind = "" + } else { + x.Kind = string(r.DecodeString()) + } + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.APIVersion = "" + } else { + x.APIVersion = string(r.DecodeString()) + } + for { + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + break + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + z.DecStructFieldNotFound(yyj9-1, "") + } + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x *PetSetSpec) CodecEncodeSelf(e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + if x == nil { + r.EncodeNil() + } else { + yym1 := z.EncBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.EncExt(x) { + } else { + yysep2 := !z.EncBinary() + yy2arr2 := z.EncBasicHandle().StructToArray + var yyq2 [5]bool + _, _, _ = yysep2, yyq2, yy2arr2 + const yyr2 bool = false + yyq2[0] = x.Replicas != 0 + yyq2[1] = x.Selector != nil + yyq2[3] = len(x.VolumeClaimTemplates) != 0 + var yynn2 int + if yyr2 || yy2arr2 { + r.EncodeArrayStart(5) + } else { + yynn2 = 2 + for _, b := range yyq2 { + if b { + yynn2++ + } + } + r.EncodeMapStart(yynn2) + yynn2 = 0 + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[0] { + yym4 := z.EncBinary() + _ = yym4 + if false { + } else { + r.EncodeInt(int64(x.Replicas)) + } + } else { + r.EncodeInt(0) + } + } else { + if yyq2[0] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("replicas")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym5 := z.EncBinary() + _ = yym5 + if false { + } else { + r.EncodeInt(int64(x.Replicas)) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[1] { + if x.Selector == nil { + r.EncodeNil() + } else { + yym7 := z.EncBinary() + _ = yym7 + if false { + } else if z.HasExtensions() && z.EncExt(x.Selector) { + } else { + z.EncFallback(x.Selector) + } + } + } else { + r.EncodeNil() + } + } else { + if yyq2[1] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("selector")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + if x.Selector == nil { + r.EncodeNil() + } else { + yym8 := z.EncBinary() + _ = yym8 + if false { + } else if z.HasExtensions() && z.EncExt(x.Selector) { + } else { + z.EncFallback(x.Selector) + } + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + yy10 := &x.Template + yy10.CodecEncodeSelf(e) + } else { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("template")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yy12 := &x.Template + yy12.CodecEncodeSelf(e) + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[3] { + if x.VolumeClaimTemplates == nil { + r.EncodeNil() + } else { + yym15 := z.EncBinary() + _ = yym15 + if false { + } else { + h.encSliceapi_PersistentVolumeClaim(([]pkg2_api.PersistentVolumeClaim)(x.VolumeClaimTemplates), e) + } + } + } else { + r.EncodeNil() + } + } else { + if yyq2[3] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("volumeClaimTemplates")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + if x.VolumeClaimTemplates == nil { + r.EncodeNil() + } else { + yym16 := z.EncBinary() + _ = yym16 + if false { + } else { + h.encSliceapi_PersistentVolumeClaim(([]pkg2_api.PersistentVolumeClaim)(x.VolumeClaimTemplates), e) + } + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + yym18 := z.EncBinary() + _ = yym18 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.ServiceName)) + } + } else { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("serviceName")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym19 := z.EncBinary() + _ = yym19 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.ServiceName)) + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + z.EncSendContainerState(codecSelfer_containerMapEnd1234) + } + } + } +} + +func (x *PetSetSpec) CodecDecodeSelf(d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + yym1 := z.DecBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.DecExt(x) { + } else { + yyct2 := r.ContainerType() + if yyct2 == codecSelferValueTypeMap1234 { + yyl2 := r.ReadMapStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerMapEnd1234) + } else { + x.codecDecodeSelfFromMap(yyl2, d) + } + } else if yyct2 == codecSelferValueTypeArray1234 { + yyl2 := r.ReadArrayStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + x.codecDecodeSelfFromArray(yyl2, d) + } + } else { + panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234) + } + } +} + +func (x *PetSetSpec) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yys3Slc = z.DecScratchBuffer() // default slice to decode into + _ = yys3Slc + var yyhl3 bool = l >= 0 + for yyj3 := 0; ; yyj3++ { + if yyhl3 { + if yyj3 >= l { + break + } + } else { + if r.CheckBreak() { + break + } + } + z.DecSendContainerState(codecSelfer_containerMapKey1234) + yys3Slc = r.DecodeBytes(yys3Slc, true, true) + yys3 := string(yys3Slc) + z.DecSendContainerState(codecSelfer_containerMapValue1234) + switch yys3 { + case "replicas": + if r.TryDecodeAsNil() { + x.Replicas = 0 + } else { + x.Replicas = int(r.DecodeInt(codecSelferBitsize1234)) + } + case "selector": + if r.TryDecodeAsNil() { + if x.Selector != nil { + x.Selector = nil + } + } else { + if x.Selector == nil { + x.Selector = new(pkg1_unversioned.LabelSelector) + } + yym6 := z.DecBinary() + _ = yym6 + if false { + } else if z.HasExtensions() && z.DecExt(x.Selector) { + } else { + z.DecFallback(x.Selector, false) + } + } + case "template": + if r.TryDecodeAsNil() { + x.Template = pkg2_api.PodTemplateSpec{} + } else { + yyv7 := &x.Template + yyv7.CodecDecodeSelf(d) + } + case "volumeClaimTemplates": + if r.TryDecodeAsNil() { + x.VolumeClaimTemplates = nil + } else { + yyv8 := &x.VolumeClaimTemplates + yym9 := z.DecBinary() + _ = yym9 + if false { + } else { + h.decSliceapi_PersistentVolumeClaim((*[]pkg2_api.PersistentVolumeClaim)(yyv8), d) + } + } + case "serviceName": + if r.TryDecodeAsNil() { + x.ServiceName = "" + } else { + x.ServiceName = string(r.DecodeString()) + } + default: + z.DecStructFieldNotFound(-1, yys3) + } // end switch yys3 + } // end for yyj3 + z.DecSendContainerState(codecSelfer_containerMapEnd1234) +} + +func (x *PetSetSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yyj11 int + var yyb11 bool + var yyhl11 bool = l >= 0 + yyj11++ + if yyhl11 { + yyb11 = yyj11 > l + } else { + yyb11 = r.CheckBreak() + } + if yyb11 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Replicas = 0 + } else { + x.Replicas = int(r.DecodeInt(codecSelferBitsize1234)) + } + yyj11++ + if yyhl11 { + yyb11 = yyj11 > l + } else { + yyb11 = r.CheckBreak() + } + if yyb11 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + if x.Selector != nil { + x.Selector = nil + } + } else { + if x.Selector == nil { + x.Selector = new(pkg1_unversioned.LabelSelector) + } + yym14 := z.DecBinary() + _ = yym14 + if false { + } else if z.HasExtensions() && z.DecExt(x.Selector) { + } else { + z.DecFallback(x.Selector, false) + } + } + yyj11++ + if yyhl11 { + yyb11 = yyj11 > l + } else { + yyb11 = r.CheckBreak() + } + if yyb11 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Template = pkg2_api.PodTemplateSpec{} + } else { + yyv15 := &x.Template + yyv15.CodecDecodeSelf(d) + } + yyj11++ + if yyhl11 { + yyb11 = yyj11 > l + } else { + yyb11 = r.CheckBreak() + } + if yyb11 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.VolumeClaimTemplates = nil + } else { + yyv16 := &x.VolumeClaimTemplates + yym17 := z.DecBinary() + _ = yym17 + if false { + } else { + h.decSliceapi_PersistentVolumeClaim((*[]pkg2_api.PersistentVolumeClaim)(yyv16), d) + } + } + yyj11++ + if yyhl11 { + yyb11 = yyj11 > l + } else { + yyb11 = r.CheckBreak() + } + if yyb11 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.ServiceName = "" + } else { + x.ServiceName = string(r.DecodeString()) + } + for { + yyj11++ + if yyhl11 { + yyb11 = yyj11 > l + } else { + yyb11 = r.CheckBreak() + } + if yyb11 { + break + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + z.DecStructFieldNotFound(yyj11-1, "") + } + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x *PetSetStatus) CodecEncodeSelf(e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + if x == nil { + r.EncodeNil() + } else { + yym1 := z.EncBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.EncExt(x) { + } else { + yysep2 := !z.EncBinary() + yy2arr2 := z.EncBasicHandle().StructToArray + var yyq2 [2]bool + _, _, _ = yysep2, yyq2, yy2arr2 + const yyr2 bool = false + yyq2[0] = x.ObservedGeneration != nil + var yynn2 int + if yyr2 || yy2arr2 { + r.EncodeArrayStart(2) + } else { + yynn2 = 1 + for _, b := range yyq2 { + if b { + yynn2++ + } + } + r.EncodeMapStart(yynn2) + yynn2 = 0 + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[0] { + if x.ObservedGeneration == nil { + r.EncodeNil() + } else { + yy4 := *x.ObservedGeneration + yym5 := z.EncBinary() + _ = yym5 + if false { + } else { + r.EncodeInt(int64(yy4)) + } + } + } else { + r.EncodeNil() + } + } else { + if yyq2[0] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("observedGeneration")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + if x.ObservedGeneration == nil { + r.EncodeNil() + } else { + yy6 := *x.ObservedGeneration + yym7 := z.EncBinary() + _ = yym7 + if false { + } else { + r.EncodeInt(int64(yy6)) + } + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + yym9 := z.EncBinary() + _ = yym9 + if false { + } else { + r.EncodeInt(int64(x.Replicas)) + } + } else { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("replicas")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym10 := z.EncBinary() + _ = yym10 + if false { + } else { + r.EncodeInt(int64(x.Replicas)) + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + z.EncSendContainerState(codecSelfer_containerMapEnd1234) + } + } + } +} + +func (x *PetSetStatus) CodecDecodeSelf(d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + yym1 := z.DecBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.DecExt(x) { + } else { + yyct2 := r.ContainerType() + if yyct2 == codecSelferValueTypeMap1234 { + yyl2 := r.ReadMapStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerMapEnd1234) + } else { + x.codecDecodeSelfFromMap(yyl2, d) + } + } else if yyct2 == codecSelferValueTypeArray1234 { + yyl2 := r.ReadArrayStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + x.codecDecodeSelfFromArray(yyl2, d) + } + } else { + panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234) + } + } +} + +func (x *PetSetStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yys3Slc = z.DecScratchBuffer() // default slice to decode into + _ = yys3Slc + var yyhl3 bool = l >= 0 + for yyj3 := 0; ; yyj3++ { + if yyhl3 { + if yyj3 >= l { + break + } + } else { + if r.CheckBreak() { + break + } + } + z.DecSendContainerState(codecSelfer_containerMapKey1234) + yys3Slc = r.DecodeBytes(yys3Slc, true, true) + yys3 := string(yys3Slc) + z.DecSendContainerState(codecSelfer_containerMapValue1234) + switch yys3 { + case "observedGeneration": + if r.TryDecodeAsNil() { + if x.ObservedGeneration != nil { + x.ObservedGeneration = nil + } + } else { + if x.ObservedGeneration == nil { + x.ObservedGeneration = new(int64) + } + yym5 := z.DecBinary() + _ = yym5 + if false { + } else { + *((*int64)(x.ObservedGeneration)) = int64(r.DecodeInt(64)) + } + } + case "replicas": + if r.TryDecodeAsNil() { + x.Replicas = 0 + } else { + x.Replicas = int(r.DecodeInt(codecSelferBitsize1234)) + } + default: + z.DecStructFieldNotFound(-1, yys3) + } // end switch yys3 + } // end for yyj3 + z.DecSendContainerState(codecSelfer_containerMapEnd1234) +} + +func (x *PetSetStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yyj7 int + var yyb7 bool + var yyhl7 bool = l >= 0 + yyj7++ + if yyhl7 { + yyb7 = yyj7 > l + } else { + yyb7 = r.CheckBreak() + } + if yyb7 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + if x.ObservedGeneration != nil { + x.ObservedGeneration = nil + } + } else { + if x.ObservedGeneration == nil { + x.ObservedGeneration = new(int64) + } + yym9 := z.DecBinary() + _ = yym9 + if false { + } else { + *((*int64)(x.ObservedGeneration)) = int64(r.DecodeInt(64)) + } + } + yyj7++ + if yyhl7 { + yyb7 = yyj7 > l + } else { + yyb7 = r.CheckBreak() + } + if yyb7 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Replicas = 0 + } else { + x.Replicas = int(r.DecodeInt(codecSelferBitsize1234)) + } + for { + yyj7++ + if yyhl7 { + yyb7 = yyj7 > l + } else { + yyb7 = r.CheckBreak() + } + if yyb7 { + break + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + z.DecStructFieldNotFound(yyj7-1, "") + } + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x *PetSetList) CodecEncodeSelf(e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + if x == nil { + r.EncodeNil() + } else { + yym1 := z.EncBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.EncExt(x) { + } else { + yysep2 := !z.EncBinary() + yy2arr2 := z.EncBasicHandle().StructToArray + var yyq2 [4]bool + _, _, _ = yysep2, yyq2, yy2arr2 + const yyr2 bool = false + yyq2[0] = true + yyq2[2] = x.Kind != "" + yyq2[3] = x.APIVersion != "" + var yynn2 int + if yyr2 || yy2arr2 { + r.EncodeArrayStart(4) + } else { + yynn2 = 1 + for _, b := range yyq2 { + if b { + yynn2++ + } + } + r.EncodeMapStart(yynn2) + yynn2 = 0 + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[0] { + yy4 := &x.ListMeta + yym5 := z.EncBinary() + _ = yym5 + if false { + } else if z.HasExtensions() && z.EncExt(yy4) { + } else { + z.EncFallback(yy4) + } + } else { + r.EncodeNil() + } + } else { + if yyq2[0] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("metadata")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yy6 := &x.ListMeta + yym7 := z.EncBinary() + _ = yym7 + if false { + } else if z.HasExtensions() && z.EncExt(yy6) { + } else { + z.EncFallback(yy6) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if x.Items == nil { + r.EncodeNil() + } else { + yym9 := z.EncBinary() + _ = yym9 + if false { + } else { + h.encSlicePetSet(([]PetSet)(x.Items), e) + } + } + } else { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("items")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + if x.Items == nil { + r.EncodeNil() + } else { + yym10 := z.EncBinary() + _ = yym10 + if false { + } else { + h.encSlicePetSet(([]PetSet)(x.Items), e) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[2] { + yym12 := z.EncBinary() + _ = yym12 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.Kind)) + } + } else { + r.EncodeString(codecSelferC_UTF81234, "") + } + } else { + if yyq2[2] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("kind")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym13 := z.EncBinary() + _ = yym13 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.Kind)) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[3] { + yym15 := z.EncBinary() + _ = yym15 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion)) + } + } else { + r.EncodeString(codecSelferC_UTF81234, "") + } + } else { + if yyq2[3] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("apiVersion")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym16 := z.EncBinary() + _ = yym16 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion)) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + z.EncSendContainerState(codecSelfer_containerMapEnd1234) + } + } + } +} + +func (x *PetSetList) CodecDecodeSelf(d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + yym1 := z.DecBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.DecExt(x) { + } else { + yyct2 := r.ContainerType() + if yyct2 == codecSelferValueTypeMap1234 { + yyl2 := r.ReadMapStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerMapEnd1234) + } else { + x.codecDecodeSelfFromMap(yyl2, d) + } + } else if yyct2 == codecSelferValueTypeArray1234 { + yyl2 := r.ReadArrayStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + x.codecDecodeSelfFromArray(yyl2, d) + } + } else { + panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234) + } + } +} + +func (x *PetSetList) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yys3Slc = z.DecScratchBuffer() // default slice to decode into + _ = yys3Slc + var yyhl3 bool = l >= 0 + for yyj3 := 0; ; yyj3++ { + if yyhl3 { + if yyj3 >= l { + break + } + } else { + if r.CheckBreak() { + break + } + } + z.DecSendContainerState(codecSelfer_containerMapKey1234) + yys3Slc = r.DecodeBytes(yys3Slc, true, true) + yys3 := string(yys3Slc) + z.DecSendContainerState(codecSelfer_containerMapValue1234) + switch yys3 { + case "metadata": + if r.TryDecodeAsNil() { + x.ListMeta = pkg1_unversioned.ListMeta{} + } else { + yyv4 := &x.ListMeta + yym5 := z.DecBinary() + _ = yym5 + if false { + } else if z.HasExtensions() && z.DecExt(yyv4) { + } else { + z.DecFallback(yyv4, false) + } + } + case "items": + if r.TryDecodeAsNil() { + x.Items = nil + } else { + yyv6 := &x.Items + yym7 := z.DecBinary() + _ = yym7 + if false { + } else { + h.decSlicePetSet((*[]PetSet)(yyv6), d) + } + } + case "kind": + if r.TryDecodeAsNil() { + x.Kind = "" + } else { + x.Kind = string(r.DecodeString()) + } + case "apiVersion": + if r.TryDecodeAsNil() { + x.APIVersion = "" + } else { + x.APIVersion = string(r.DecodeString()) + } + default: + z.DecStructFieldNotFound(-1, yys3) + } // end switch yys3 + } // end for yyj3 + z.DecSendContainerState(codecSelfer_containerMapEnd1234) +} + +func (x *PetSetList) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yyj10 int + var yyb10 bool + var yyhl10 bool = l >= 0 + yyj10++ + if yyhl10 { + yyb10 = yyj10 > l + } else { + yyb10 = r.CheckBreak() + } + if yyb10 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.ListMeta = pkg1_unversioned.ListMeta{} + } else { + yyv11 := &x.ListMeta + yym12 := z.DecBinary() + _ = yym12 + if false { + } else if z.HasExtensions() && z.DecExt(yyv11) { + } else { + z.DecFallback(yyv11, false) + } + } + yyj10++ + if yyhl10 { + yyb10 = yyj10 > l + } else { + yyb10 = r.CheckBreak() + } + if yyb10 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Items = nil + } else { + yyv13 := &x.Items + yym14 := z.DecBinary() + _ = yym14 + if false { + } else { + h.decSlicePetSet((*[]PetSet)(yyv13), d) + } + } + yyj10++ + if yyhl10 { + yyb10 = yyj10 > l + } else { + yyb10 = r.CheckBreak() + } + if yyb10 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Kind = "" + } else { + x.Kind = string(r.DecodeString()) + } + yyj10++ + if yyhl10 { + yyb10 = yyj10 > l + } else { + yyb10 = r.CheckBreak() + } + if yyb10 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.APIVersion = "" + } else { + x.APIVersion = string(r.DecodeString()) + } + for { + yyj10++ + if yyhl10 { + yyb10 = yyj10 > l + } else { + yyb10 = r.CheckBreak() + } + if yyb10 { + break + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + z.DecStructFieldNotFound(yyj10-1, "") + } + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x codecSelfer1234) encSliceapi_PersistentVolumeClaim(v []pkg2_api.PersistentVolumeClaim, e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + r.EncodeArrayStart(len(v)) + for _, yyv1 := range v { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + yy2 := &yyv1 + yy2.CodecEncodeSelf(e) + } + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x codecSelfer1234) decSliceapi_PersistentVolumeClaim(v *[]pkg2_api.PersistentVolumeClaim, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + + yyv1 := *v + yyh1, yyl1 := z.DecSliceHelperStart() + var yyc1 bool + _ = yyc1 + if yyl1 == 0 { + if yyv1 == nil { + yyv1 = []pkg2_api.PersistentVolumeClaim{} + yyc1 = true + } else if len(yyv1) != 0 { + yyv1 = yyv1[:0] + yyc1 = true + } + } else if yyl1 > 0 { + var yyrr1, yyrl1 int + var yyrt1 bool + _, _ = yyrl1, yyrt1 + yyrr1 = yyl1 // len(yyv1) + if yyl1 > cap(yyv1) { + + yyrg1 := len(yyv1) > 0 + yyv21 := yyv1 + yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 296) + if yyrt1 { + if yyrl1 <= cap(yyv1) { + yyv1 = yyv1[:yyrl1] + } else { + yyv1 = make([]pkg2_api.PersistentVolumeClaim, yyrl1) + } + } else { + yyv1 = make([]pkg2_api.PersistentVolumeClaim, yyrl1) + } + yyc1 = true + yyrr1 = len(yyv1) + if yyrg1 { + copy(yyv1, yyv21) + } + } else if yyl1 != len(yyv1) { + yyv1 = yyv1[:yyl1] + yyc1 = true + } + yyj1 := 0 + for ; yyj1 < yyrr1; yyj1++ { + yyh1.ElemContainerState(yyj1) + if r.TryDecodeAsNil() { + yyv1[yyj1] = pkg2_api.PersistentVolumeClaim{} + } else { + yyv2 := &yyv1[yyj1] + yyv2.CodecDecodeSelf(d) + } + + } + if yyrt1 { + for ; yyj1 < yyl1; yyj1++ { + yyv1 = append(yyv1, pkg2_api.PersistentVolumeClaim{}) + yyh1.ElemContainerState(yyj1) + if r.TryDecodeAsNil() { + yyv1[yyj1] = pkg2_api.PersistentVolumeClaim{} + } else { + yyv3 := &yyv1[yyj1] + yyv3.CodecDecodeSelf(d) + } + + } + } + + } else { + yyj1 := 0 + for ; !r.CheckBreak(); yyj1++ { + + if yyj1 >= len(yyv1) { + yyv1 = append(yyv1, pkg2_api.PersistentVolumeClaim{}) // var yyz1 pkg2_api.PersistentVolumeClaim + yyc1 = true + } + yyh1.ElemContainerState(yyj1) + if yyj1 < len(yyv1) { + if r.TryDecodeAsNil() { + yyv1[yyj1] = pkg2_api.PersistentVolumeClaim{} + } else { + yyv4 := &yyv1[yyj1] + yyv4.CodecDecodeSelf(d) + } + + } else { + z.DecSwallow() + } + + } + if yyj1 < len(yyv1) { + yyv1 = yyv1[:yyj1] + yyc1 = true + } else if yyj1 == 0 && yyv1 == nil { + yyv1 = []pkg2_api.PersistentVolumeClaim{} + yyc1 = true + } + } + yyh1.End() + if yyc1 { + *v = yyv1 + } +} + +func (x codecSelfer1234) encSlicePetSet(v []PetSet, e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + r.EncodeArrayStart(len(v)) + for _, yyv1 := range v { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + yy2 := &yyv1 + yy2.CodecEncodeSelf(e) + } + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x codecSelfer1234) decSlicePetSet(v *[]PetSet, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + + yyv1 := *v + yyh1, yyl1 := z.DecSliceHelperStart() + var yyc1 bool + _ = yyc1 + if yyl1 == 0 { + if yyv1 == nil { + yyv1 = []PetSet{} + yyc1 = true + } else if len(yyv1) != 0 { + yyv1 = yyv1[:0] + yyc1 = true + } + } else if yyl1 > 0 { + var yyrr1, yyrl1 int + var yyrt1 bool + _, _ = yyrl1, yyrt1 + yyrr1 = yyl1 // len(yyv1) + if yyl1 > cap(yyv1) { + + yyrg1 := len(yyv1) > 0 + yyv21 := yyv1 + yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 592) + if yyrt1 { + if yyrl1 <= cap(yyv1) { + yyv1 = yyv1[:yyrl1] + } else { + yyv1 = make([]PetSet, yyrl1) + } + } else { + yyv1 = make([]PetSet, yyrl1) + } + yyc1 = true + yyrr1 = len(yyv1) + if yyrg1 { + copy(yyv1, yyv21) + } + } else if yyl1 != len(yyv1) { + yyv1 = yyv1[:yyl1] + yyc1 = true + } + yyj1 := 0 + for ; yyj1 < yyrr1; yyj1++ { + yyh1.ElemContainerState(yyj1) + if r.TryDecodeAsNil() { + yyv1[yyj1] = PetSet{} + } else { + yyv2 := &yyv1[yyj1] + yyv2.CodecDecodeSelf(d) + } + + } + if yyrt1 { + for ; yyj1 < yyl1; yyj1++ { + yyv1 = append(yyv1, PetSet{}) + yyh1.ElemContainerState(yyj1) + if r.TryDecodeAsNil() { + yyv1[yyj1] = PetSet{} + } else { + yyv3 := &yyv1[yyj1] + yyv3.CodecDecodeSelf(d) + } + + } + } + + } else { + yyj1 := 0 + for ; !r.CheckBreak(); yyj1++ { + + if yyj1 >= len(yyv1) { + yyv1 = append(yyv1, PetSet{}) // var yyz1 PetSet + yyc1 = true + } + yyh1.ElemContainerState(yyj1) + if yyj1 < len(yyv1) { + if r.TryDecodeAsNil() { + yyv1[yyj1] = PetSet{} + } else { + yyv4 := &yyv1[yyj1] + yyv4.CodecDecodeSelf(d) + } + + } else { + z.DecSwallow() + } + + } + if yyj1 < len(yyv1) { + yyv1 = yyv1[:yyj1] + yyc1 = true + } else if yyj1 == 0 && yyv1 == nil { + yyv1 = []PetSet{} + yyc1 = true + } + } + yyh1.End() + if yyc1 { + *v = yyv1 + } +} diff --git a/pkg/apis/apps/types.go b/pkg/apis/apps/types.go new file mode 100644 index 00000000000..f140cab96e5 --- /dev/null +++ b/pkg/apis/apps/types.go @@ -0,0 +1,94 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 apps + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" +) + +// PetSet represents a set of pods with consistent identities. +// Identities are defined as: +// - Network: A single stable DNS and hostname. +// - Storage: As many VolumeClaims as requested. +// The PetSet guarantees that a given network identity will always +// map to the same storage identity. PetSet is currently in alpha and +// and subject to change without notice. +type PetSet struct { + unversioned.TypeMeta `json:",inline"` + api.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired identities of pets in this set. + Spec PetSetSpec `json:"spec,omitempty"` + + // Status is the current status of Pets in this PetSet. This data + // may be out of date by some window of time. + Status PetSetStatus `json:"status,omitempty"` +} + +// A PetSetSpec is the specification of a PetSet. +type PetSetSpec struct { + // Replicas is the desired number of replicas of the given Template. + // These are replicas in the sense that they are instantiations of the + // same Template, but individual replicas also have a consistent identity. + // If unspecified, defaults to 1. + // TODO: Consider a rename of this field. + Replicas int `json:"replicas,omitempty"` + + // Selector is a label query over pods that should match the replica count. + // If empty, defaulted to labels on the pod template. + // More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors + Selector *unversioned.LabelSelector `json:"selector,omitempty"` + + // Template is the object that describes the pod that will be created if + // insufficient replicas are detected. Each pod stamped out by the PetSet + // will fulfill this Template, but have a unique identity from the rest + // of the PetSet. + Template api.PodTemplateSpec `json:"template"` + + // VolumeClaimTemplates is a list of claims that pets are allowed to reference. + // The PetSet controller is responsible for mapping network identities to + // claims in a way that maintains the identity of a pet. Every claim in + // this list must have at least one matching (by name) volumeMount in one + // container in the template. A claim in this list takes precedence over + // any volumes in the template, with the same name. + // TODO: Define the behavior if a claim already exists with the same name. + VolumeClaimTemplates []api.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty"` + + // ServiceName is the name of the service that governs this PetSet. + // This service must exist before the PetSet, and is responsible for + // the network identity of the set. Pets get DNS/hostnames that follow the + // pattern: pet-specific-string.serviceName.default.svc.cluster.local + // where "pet-specific-string" is managed by the PetSet controller. + ServiceName string `json:"serviceName"` +} + +// PetSetStatus represents the current state of a PetSet. +type PetSetStatus struct { + // most recent generation observed by this autoscaler. + ObservedGeneration *int64 `json:"observedGeneration,omitempty"` + + // Replicas is the number of actual replicas. + Replicas int `json:"replicas"` +} + +// PetSetList is a collection of PetSets. +type PetSetList struct { + unversioned.TypeMeta `json:",inline"` + unversioned.ListMeta `json:"metadata,omitempty"` + Items []PetSet `json:"items"` +} diff --git a/pkg/apis/apps/v1alpha1/conversion.go b/pkg/apis/apps/v1alpha1/conversion.go new file mode 100644 index 00000000000..505a26cc937 --- /dev/null +++ b/pkg/apis/apps/v1alpha1/conversion.go @@ -0,0 +1,125 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 v1alpha1 + +import ( + "fmt" + "reflect" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + v1 "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/conversion" + "k8s.io/kubernetes/pkg/runtime" +) + +func addConversionFuncs(scheme *runtime.Scheme) { + // Add non-generated conversion functions to handle the *int32 -> int + // conversion. A pointer is useful in the versioned type so we can default + // it, but a plain int32 is more convenient in the internal type. These + // functions are the same as the autogenerated ones in every other way. + err := scheme.AddConversionFuncs( + Convert_v1alpha1_PetSetSpec_To_apps_PetSetSpec, + Convert_apps_PetSetSpec_To_v1alpha1_PetSetSpec, + ) + if err != nil { + // If one of the conversion functions is malformed, detect it immediately. + panic(err) + } + + err = api.Scheme.AddFieldLabelConversionFunc("apps/v1alpha1", "PetSet", + func(label, value string) (string, string, error) { + switch label { + case "metadata.name", "metadata.namespace", "status.successful": + return label, value, nil + default: + return "", "", fmt.Errorf("field label not supported: %s", label) + } + }) + if err != nil { + // If one of the conversion functions is malformed, detect it immediately. + panic(err) + } +} + +func Convert_v1alpha1_PetSetSpec_To_apps_PetSetSpec(in *PetSetSpec, out *apps.PetSetSpec, s conversion.Scope) error { + if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { + defaulting.(func(*PetSetSpec))(in) + } + if in.Replicas != nil { + out.Replicas = int(*in.Replicas) + } + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(unversioned.LabelSelector) + if err := s.Convert(*in, *out, 0); err != nil { + return err + } + } else { + out.Selector = nil + } + if err := s.Convert(&in.Template, &out.Template, 0); err != nil { + return err + } + if in.VolumeClaimTemplates != nil { + in, out := &in.VolumeClaimTemplates, &out.VolumeClaimTemplates + *out = make([]api.PersistentVolumeClaim, len(*in)) + for i := range *in { + if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil { + return err + } + } + } else { + out.VolumeClaimTemplates = nil + } + out.ServiceName = in.ServiceName + return nil +} + +func Convert_apps_PetSetSpec_To_v1alpha1_PetSetSpec(in *apps.PetSetSpec, out *PetSetSpec, s conversion.Scope) error { + if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { + defaulting.(func(*apps.PetSetSpec))(in) + } + out.Replicas = new(int32) + *out.Replicas = int32(in.Replicas) + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(unversioned.LabelSelector) + if err := s.Convert(*in, *out, 0); err != nil { + return err + } + } else { + out.Selector = nil + } + if err := s.Convert(&in.Template, &out.Template, 0); err != nil { + return err + } + if in.VolumeClaimTemplates != nil { + in, out := &in.VolumeClaimTemplates, &out.VolumeClaimTemplates + *out = make([]v1.PersistentVolumeClaim, len(*in)) + for i := range *in { + if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil { + return err + } + } + } else { + out.VolumeClaimTemplates = nil + } + out.ServiceName = in.ServiceName + return nil +} diff --git a/pkg/apis/apps/v1alpha1/conversion_generated.go b/pkg/apis/apps/v1alpha1/conversion_generated.go new file mode 100644 index 00000000000..795a787a8bf --- /dev/null +++ b/pkg/apis/apps/v1alpha1/conversion_generated.go @@ -0,0 +1,186 @@ +// +build !ignore_autogenerated + +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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. +*/ + +// This file was autogenerated by conversion-gen. Do not edit it manually! + +package v1alpha1 + +import ( + api "k8s.io/kubernetes/pkg/api" + apps "k8s.io/kubernetes/pkg/apis/apps" + conversion "k8s.io/kubernetes/pkg/conversion" + reflect "reflect" +) + +func init() { + if err := api.Scheme.AddGeneratedConversionFuncs( + Convert_v1alpha1_PetSet_To_apps_PetSet, + Convert_apps_PetSet_To_v1alpha1_PetSet, + Convert_v1alpha1_PetSetList_To_apps_PetSetList, + Convert_apps_PetSetList_To_v1alpha1_PetSetList, + Convert_v1alpha1_PetSetSpec_To_apps_PetSetSpec, + Convert_apps_PetSetSpec_To_v1alpha1_PetSetSpec, + Convert_v1alpha1_PetSetStatus_To_apps_PetSetStatus, + Convert_apps_PetSetStatus_To_v1alpha1_PetSetStatus, + ); err != nil { + // if one of the conversion functions is malformed, detect it immediately. + panic(err) + } +} + +func autoConvert_v1alpha1_PetSet_To_apps_PetSet(in *PetSet, out *apps.PetSet, s conversion.Scope) error { + if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { + defaulting.(func(*PetSet))(in) + } + if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil { + return err + } + // TODO: Inefficient conversion - can we improve it? + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := Convert_v1alpha1_PetSetSpec_To_apps_PetSetSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1alpha1_PetSetStatus_To_apps_PetSetStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +func Convert_v1alpha1_PetSet_To_apps_PetSet(in *PetSet, out *apps.PetSet, s conversion.Scope) error { + return autoConvert_v1alpha1_PetSet_To_apps_PetSet(in, out, s) +} + +func autoConvert_apps_PetSet_To_v1alpha1_PetSet(in *apps.PetSet, out *PetSet, s conversion.Scope) error { + if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { + defaulting.(func(*apps.PetSet))(in) + } + if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil { + return err + } + // TODO: Inefficient conversion - can we improve it? + if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil { + return err + } + if err := Convert_apps_PetSetSpec_To_v1alpha1_PetSetSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_apps_PetSetStatus_To_v1alpha1_PetSetStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +func Convert_apps_PetSet_To_v1alpha1_PetSet(in *apps.PetSet, out *PetSet, s conversion.Scope) error { + return autoConvert_apps_PetSet_To_v1alpha1_PetSet(in, out, s) +} + +func autoConvert_v1alpha1_PetSetList_To_apps_PetSetList(in *PetSetList, out *apps.PetSetList, s conversion.Scope) error { + if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { + defaulting.(func(*PetSetList))(in) + } + if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil { + return err + } + if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil { + return err + } + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]apps.PetSet, len(*in)) + for i := range *in { + if err := Convert_v1alpha1_PetSet_To_apps_PetSet(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +func Convert_v1alpha1_PetSetList_To_apps_PetSetList(in *PetSetList, out *apps.PetSetList, s conversion.Scope) error { + return autoConvert_v1alpha1_PetSetList_To_apps_PetSetList(in, out, s) +} + +func autoConvert_apps_PetSetList_To_v1alpha1_PetSetList(in *apps.PetSetList, out *PetSetList, s conversion.Scope) error { + if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { + defaulting.(func(*apps.PetSetList))(in) + } + if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil { + return err + } + if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil { + return err + } + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PetSet, len(*in)) + for i := range *in { + if err := Convert_apps_PetSet_To_v1alpha1_PetSet(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +func Convert_apps_PetSetList_To_v1alpha1_PetSetList(in *apps.PetSetList, out *PetSetList, s conversion.Scope) error { + return autoConvert_apps_PetSetList_To_v1alpha1_PetSetList(in, out, s) +} + +func autoConvert_v1alpha1_PetSetStatus_To_apps_PetSetStatus(in *PetSetStatus, out *apps.PetSetStatus, s conversion.Scope) error { + if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { + defaulting.(func(*PetSetStatus))(in) + } + if in.ObservedGeneration != nil { + in, out := &in.ObservedGeneration, &out.ObservedGeneration + *out = new(int64) + **out = **in + } else { + out.ObservedGeneration = nil + } + out.Replicas = int(in.Replicas) + return nil +} + +func Convert_v1alpha1_PetSetStatus_To_apps_PetSetStatus(in *PetSetStatus, out *apps.PetSetStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_PetSetStatus_To_apps_PetSetStatus(in, out, s) +} + +func autoConvert_apps_PetSetStatus_To_v1alpha1_PetSetStatus(in *apps.PetSetStatus, out *PetSetStatus, s conversion.Scope) error { + if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { + defaulting.(func(*apps.PetSetStatus))(in) + } + if in.ObservedGeneration != nil { + in, out := &in.ObservedGeneration, &out.ObservedGeneration + *out = new(int64) + **out = **in + } else { + out.ObservedGeneration = nil + } + out.Replicas = int32(in.Replicas) + return nil +} + +func Convert_apps_PetSetStatus_To_v1alpha1_PetSetStatus(in *apps.PetSetStatus, out *PetSetStatus, s conversion.Scope) error { + return autoConvert_apps_PetSetStatus_To_v1alpha1_PetSetStatus(in, out, s) +} diff --git a/pkg/apis/apps/v1alpha1/deep_copy_generated.go b/pkg/apis/apps/v1alpha1/deep_copy_generated.go new file mode 100644 index 00000000000..6e51cacbc25 --- /dev/null +++ b/pkg/apis/apps/v1alpha1/deep_copy_generated.go @@ -0,0 +1,124 @@ +// +build !ignore_autogenerated + +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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. +*/ + +// This file was autogenerated by deepcopy-gen. Do not edit it manually! + +package v1alpha1 + +import ( + api "k8s.io/kubernetes/pkg/api" + unversioned "k8s.io/kubernetes/pkg/api/unversioned" + v1 "k8s.io/kubernetes/pkg/api/v1" + conversion "k8s.io/kubernetes/pkg/conversion" +) + +func init() { + if err := api.Scheme.AddGeneratedDeepCopyFuncs( + DeepCopy_v1alpha1_PetSet, + DeepCopy_v1alpha1_PetSetList, + DeepCopy_v1alpha1_PetSetSpec, + DeepCopy_v1alpha1_PetSetStatus, + ); err != nil { + // if one of the deep copy functions is malformed, detect it immediately. + panic(err) + } +} + +func DeepCopy_v1alpha1_PetSet(in PetSet, out *PetSet, c *conversion.Cloner) error { + if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil { + return err + } + if err := v1.DeepCopy_v1_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil { + return err + } + if err := DeepCopy_v1alpha1_PetSetSpec(in.Spec, &out.Spec, c); err != nil { + return err + } + if err := DeepCopy_v1alpha1_PetSetStatus(in.Status, &out.Status, c); err != nil { + return err + } + return nil +} + +func DeepCopy_v1alpha1_PetSetList(in PetSetList, out *PetSetList, c *conversion.Cloner) error { + if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil { + return err + } + if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil { + return err + } + if in.Items != nil { + in, out := in.Items, &out.Items + *out = make([]PetSet, len(in)) + for i := range in { + if err := DeepCopy_v1alpha1_PetSet(in[i], &(*out)[i], c); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +func DeepCopy_v1alpha1_PetSetSpec(in PetSetSpec, out *PetSetSpec, c *conversion.Cloner) error { + if in.Replicas != nil { + in, out := in.Replicas, &out.Replicas + *out = new(int32) + **out = *in + } else { + out.Replicas = nil + } + if in.Selector != nil { + in, out := in.Selector, &out.Selector + *out = new(unversioned.LabelSelector) + if err := unversioned.DeepCopy_unversioned_LabelSelector(*in, *out, c); err != nil { + return err + } + } else { + out.Selector = nil + } + if err := v1.DeepCopy_v1_PodTemplateSpec(in.Template, &out.Template, c); err != nil { + return err + } + if in.VolumeClaimTemplates != nil { + in, out := in.VolumeClaimTemplates, &out.VolumeClaimTemplates + *out = make([]v1.PersistentVolumeClaim, len(in)) + for i := range in { + if err := v1.DeepCopy_v1_PersistentVolumeClaim(in[i], &(*out)[i], c); err != nil { + return err + } + } + } else { + out.VolumeClaimTemplates = nil + } + out.ServiceName = in.ServiceName + return nil +} + +func DeepCopy_v1alpha1_PetSetStatus(in PetSetStatus, out *PetSetStatus, c *conversion.Cloner) error { + if in.ObservedGeneration != nil { + in, out := in.ObservedGeneration, &out.ObservedGeneration + *out = new(int64) + **out = *in + } else { + out.ObservedGeneration = nil + } + out.Replicas = in.Replicas + return nil +} diff --git a/pkg/apis/apps/v1alpha1/defaulting.go b/pkg/apis/apps/v1alpha1/defaulting.go new file mode 100644 index 00000000000..c861f2466cd --- /dev/null +++ b/pkg/apis/apps/v1alpha1/defaulting.go @@ -0,0 +1,44 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 v1alpha1 + +import ( + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/runtime" +) + +func addDefaultingFuncs(scheme *runtime.Scheme) { + scheme.AddDefaultingFuncs( + func(obj *PetSet) { + labels := obj.Spec.Template.Labels + if labels != nil { + if obj.Spec.Selector == nil { + obj.Spec.Selector = &unversioned.LabelSelector{ + MatchLabels: labels, + } + } + if len(obj.Labels) == 0 { + obj.Labels = labels + } + } + if obj.Spec.Replicas == nil { + obj.Spec.Replicas = new(int32) + *obj.Spec.Replicas = 1 + } + }, + ) +} diff --git a/pkg/apis/apps/v1alpha1/doc.go b/pkg/apis/apps/v1alpha1/doc.go new file mode 100644 index 00000000000..65a03a2093d --- /dev/null +++ b/pkg/apis/apps/v1alpha1/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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. +*/ + +// +genconversion=true +package v1alpha1 diff --git a/pkg/apis/apps/v1alpha1/register.go b/pkg/apis/apps/v1alpha1/register.go new file mode 100644 index 00000000000..e069807754b --- /dev/null +++ b/pkg/apis/apps/v1alpha1/register.go @@ -0,0 +1,49 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 v1alpha1 + +import ( + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/runtime" + versionedwatch "k8s.io/kubernetes/pkg/watch/versioned" +) + +// GroupName is the group name use in this package +const GroupName = "apps" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: "v1alpha1"} + +func AddToScheme(scheme *runtime.Scheme) { + addKnownTypes(scheme) + addDefaultingFuncs(scheme) + addConversionFuncs(scheme) +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) { + scheme.AddKnownTypes(SchemeGroupVersion, + &PetSet{}, + &PetSetList{}, + &v1.ListOptions{}, + ) + versionedwatch.AddToGroupVersion(scheme, SchemeGroupVersion) +} + +func (obj *PetSet) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *PetSetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } diff --git a/pkg/apis/apps/v1alpha1/types.generated.go b/pkg/apis/apps/v1alpha1/types.generated.go new file mode 100644 index 00000000000..29f07040c2b --- /dev/null +++ b/pkg/apis/apps/v1alpha1/types.generated.go @@ -0,0 +1,1666 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +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. +*/ + +// ************************************************************ +// DO NOT EDIT. +// THIS FILE IS AUTO-GENERATED BY codecgen. +// ************************************************************ + +package v1alpha1 + +import ( + "errors" + "fmt" + codec1978 "github.com/ugorji/go/codec" + pkg4_resource "k8s.io/kubernetes/pkg/api/resource" + pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned" + pkg2_v1 "k8s.io/kubernetes/pkg/api/v1" + pkg3_types "k8s.io/kubernetes/pkg/types" + pkg6_intstr "k8s.io/kubernetes/pkg/util/intstr" + "reflect" + "runtime" + pkg5_inf "speter.net/go/exp/math/dec/inf" + time "time" +) + +const ( + // ----- content types ---- + codecSelferC_UTF81234 = 1 + codecSelferC_RAW1234 = 0 + // ----- value types used ---- + codecSelferValueTypeArray1234 = 10 + codecSelferValueTypeMap1234 = 9 + // ----- containerStateValues ---- + codecSelfer_containerMapKey1234 = 2 + codecSelfer_containerMapValue1234 = 3 + codecSelfer_containerMapEnd1234 = 4 + codecSelfer_containerArrayElem1234 = 6 + codecSelfer_containerArrayEnd1234 = 7 +) + +var ( + codecSelferBitsize1234 = uint8(reflect.TypeOf(uint(0)).Bits()) + codecSelferOnlyMapOrArrayEncodeToStructErr1234 = errors.New(`only encoded map or array can be decoded into a struct`) +) + +type codecSelfer1234 struct{} + +func init() { + if codec1978.GenVersion != 5 { + _, file, _, _ := runtime.Caller(0) + err := fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", + 5, codec1978.GenVersion, file) + panic(err) + } + if false { // reference the types, but skip this branch at build/run time + var v0 pkg4_resource.Quantity + var v1 pkg1_unversioned.TypeMeta + var v2 pkg2_v1.ObjectMeta + var v3 pkg3_types.UID + var v4 pkg6_intstr.IntOrString + var v5 pkg5_inf.Dec + var v6 time.Time + _, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6 + } +} + +func (x *PetSet) CodecEncodeSelf(e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + if x == nil { + r.EncodeNil() + } else { + yym1 := z.EncBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.EncExt(x) { + } else { + yysep2 := !z.EncBinary() + yy2arr2 := z.EncBasicHandle().StructToArray + var yyq2 [5]bool + _, _, _ = yysep2, yyq2, yy2arr2 + const yyr2 bool = false + yyq2[0] = true + yyq2[1] = true + yyq2[2] = true + yyq2[3] = x.Kind != "" + yyq2[4] = x.APIVersion != "" + var yynn2 int + if yyr2 || yy2arr2 { + r.EncodeArrayStart(5) + } else { + yynn2 = 0 + for _, b := range yyq2 { + if b { + yynn2++ + } + } + r.EncodeMapStart(yynn2) + yynn2 = 0 + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[0] { + yy4 := &x.ObjectMeta + yy4.CodecEncodeSelf(e) + } else { + r.EncodeNil() + } + } else { + if yyq2[0] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("metadata")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yy6 := &x.ObjectMeta + yy6.CodecEncodeSelf(e) + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[1] { + yy9 := &x.Spec + yy9.CodecEncodeSelf(e) + } else { + r.EncodeNil() + } + } else { + if yyq2[1] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("spec")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yy11 := &x.Spec + yy11.CodecEncodeSelf(e) + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[2] { + yy14 := &x.Status + yy14.CodecEncodeSelf(e) + } else { + r.EncodeNil() + } + } else { + if yyq2[2] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("status")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yy16 := &x.Status + yy16.CodecEncodeSelf(e) + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[3] { + yym19 := z.EncBinary() + _ = yym19 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.Kind)) + } + } else { + r.EncodeString(codecSelferC_UTF81234, "") + } + } else { + if yyq2[3] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("kind")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym20 := z.EncBinary() + _ = yym20 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.Kind)) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[4] { + yym22 := z.EncBinary() + _ = yym22 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion)) + } + } else { + r.EncodeString(codecSelferC_UTF81234, "") + } + } else { + if yyq2[4] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("apiVersion")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym23 := z.EncBinary() + _ = yym23 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion)) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + z.EncSendContainerState(codecSelfer_containerMapEnd1234) + } + } + } +} + +func (x *PetSet) CodecDecodeSelf(d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + yym1 := z.DecBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.DecExt(x) { + } else { + yyct2 := r.ContainerType() + if yyct2 == codecSelferValueTypeMap1234 { + yyl2 := r.ReadMapStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerMapEnd1234) + } else { + x.codecDecodeSelfFromMap(yyl2, d) + } + } else if yyct2 == codecSelferValueTypeArray1234 { + yyl2 := r.ReadArrayStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + x.codecDecodeSelfFromArray(yyl2, d) + } + } else { + panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234) + } + } +} + +func (x *PetSet) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yys3Slc = z.DecScratchBuffer() // default slice to decode into + _ = yys3Slc + var yyhl3 bool = l >= 0 + for yyj3 := 0; ; yyj3++ { + if yyhl3 { + if yyj3 >= l { + break + } + } else { + if r.CheckBreak() { + break + } + } + z.DecSendContainerState(codecSelfer_containerMapKey1234) + yys3Slc = r.DecodeBytes(yys3Slc, true, true) + yys3 := string(yys3Slc) + z.DecSendContainerState(codecSelfer_containerMapValue1234) + switch yys3 { + case "metadata": + if r.TryDecodeAsNil() { + x.ObjectMeta = pkg2_v1.ObjectMeta{} + } else { + yyv4 := &x.ObjectMeta + yyv4.CodecDecodeSelf(d) + } + case "spec": + if r.TryDecodeAsNil() { + x.Spec = PetSetSpec{} + } else { + yyv5 := &x.Spec + yyv5.CodecDecodeSelf(d) + } + case "status": + if r.TryDecodeAsNil() { + x.Status = PetSetStatus{} + } else { + yyv6 := &x.Status + yyv6.CodecDecodeSelf(d) + } + case "kind": + if r.TryDecodeAsNil() { + x.Kind = "" + } else { + x.Kind = string(r.DecodeString()) + } + case "apiVersion": + if r.TryDecodeAsNil() { + x.APIVersion = "" + } else { + x.APIVersion = string(r.DecodeString()) + } + default: + z.DecStructFieldNotFound(-1, yys3) + } // end switch yys3 + } // end for yyj3 + z.DecSendContainerState(codecSelfer_containerMapEnd1234) +} + +func (x *PetSet) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yyj9 int + var yyb9 bool + var yyhl9 bool = l >= 0 + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.ObjectMeta = pkg2_v1.ObjectMeta{} + } else { + yyv10 := &x.ObjectMeta + yyv10.CodecDecodeSelf(d) + } + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Spec = PetSetSpec{} + } else { + yyv11 := &x.Spec + yyv11.CodecDecodeSelf(d) + } + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Status = PetSetStatus{} + } else { + yyv12 := &x.Status + yyv12.CodecDecodeSelf(d) + } + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Kind = "" + } else { + x.Kind = string(r.DecodeString()) + } + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.APIVersion = "" + } else { + x.APIVersion = string(r.DecodeString()) + } + for { + yyj9++ + if yyhl9 { + yyb9 = yyj9 > l + } else { + yyb9 = r.CheckBreak() + } + if yyb9 { + break + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + z.DecStructFieldNotFound(yyj9-1, "") + } + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x *PetSetSpec) CodecEncodeSelf(e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + if x == nil { + r.EncodeNil() + } else { + yym1 := z.EncBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.EncExt(x) { + } else { + yysep2 := !z.EncBinary() + yy2arr2 := z.EncBasicHandle().StructToArray + var yyq2 [5]bool + _, _, _ = yysep2, yyq2, yy2arr2 + const yyr2 bool = false + yyq2[0] = x.Replicas != nil + yyq2[1] = x.Selector != nil + yyq2[3] = len(x.VolumeClaimTemplates) != 0 + var yynn2 int + if yyr2 || yy2arr2 { + r.EncodeArrayStart(5) + } else { + yynn2 = 2 + for _, b := range yyq2 { + if b { + yynn2++ + } + } + r.EncodeMapStart(yynn2) + yynn2 = 0 + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[0] { + if x.Replicas == nil { + r.EncodeNil() + } else { + yy4 := *x.Replicas + yym5 := z.EncBinary() + _ = yym5 + if false { + } else { + r.EncodeInt(int64(yy4)) + } + } + } else { + r.EncodeNil() + } + } else { + if yyq2[0] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("replicas")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + if x.Replicas == nil { + r.EncodeNil() + } else { + yy6 := *x.Replicas + yym7 := z.EncBinary() + _ = yym7 + if false { + } else { + r.EncodeInt(int64(yy6)) + } + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[1] { + if x.Selector == nil { + r.EncodeNil() + } else { + yym9 := z.EncBinary() + _ = yym9 + if false { + } else if z.HasExtensions() && z.EncExt(x.Selector) { + } else { + z.EncFallback(x.Selector) + } + } + } else { + r.EncodeNil() + } + } else { + if yyq2[1] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("selector")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + if x.Selector == nil { + r.EncodeNil() + } else { + yym10 := z.EncBinary() + _ = yym10 + if false { + } else if z.HasExtensions() && z.EncExt(x.Selector) { + } else { + z.EncFallback(x.Selector) + } + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + yy12 := &x.Template + yy12.CodecEncodeSelf(e) + } else { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("template")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yy14 := &x.Template + yy14.CodecEncodeSelf(e) + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[3] { + if x.VolumeClaimTemplates == nil { + r.EncodeNil() + } else { + yym17 := z.EncBinary() + _ = yym17 + if false { + } else { + h.encSlicev1_PersistentVolumeClaim(([]pkg2_v1.PersistentVolumeClaim)(x.VolumeClaimTemplates), e) + } + } + } else { + r.EncodeNil() + } + } else { + if yyq2[3] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("volumeClaimTemplates")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + if x.VolumeClaimTemplates == nil { + r.EncodeNil() + } else { + yym18 := z.EncBinary() + _ = yym18 + if false { + } else { + h.encSlicev1_PersistentVolumeClaim(([]pkg2_v1.PersistentVolumeClaim)(x.VolumeClaimTemplates), e) + } + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + yym20 := z.EncBinary() + _ = yym20 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.ServiceName)) + } + } else { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("serviceName")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym21 := z.EncBinary() + _ = yym21 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.ServiceName)) + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + z.EncSendContainerState(codecSelfer_containerMapEnd1234) + } + } + } +} + +func (x *PetSetSpec) CodecDecodeSelf(d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + yym1 := z.DecBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.DecExt(x) { + } else { + yyct2 := r.ContainerType() + if yyct2 == codecSelferValueTypeMap1234 { + yyl2 := r.ReadMapStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerMapEnd1234) + } else { + x.codecDecodeSelfFromMap(yyl2, d) + } + } else if yyct2 == codecSelferValueTypeArray1234 { + yyl2 := r.ReadArrayStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + x.codecDecodeSelfFromArray(yyl2, d) + } + } else { + panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234) + } + } +} + +func (x *PetSetSpec) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yys3Slc = z.DecScratchBuffer() // default slice to decode into + _ = yys3Slc + var yyhl3 bool = l >= 0 + for yyj3 := 0; ; yyj3++ { + if yyhl3 { + if yyj3 >= l { + break + } + } else { + if r.CheckBreak() { + break + } + } + z.DecSendContainerState(codecSelfer_containerMapKey1234) + yys3Slc = r.DecodeBytes(yys3Slc, true, true) + yys3 := string(yys3Slc) + z.DecSendContainerState(codecSelfer_containerMapValue1234) + switch yys3 { + case "replicas": + if r.TryDecodeAsNil() { + if x.Replicas != nil { + x.Replicas = nil + } + } else { + if x.Replicas == nil { + x.Replicas = new(int32) + } + yym5 := z.DecBinary() + _ = yym5 + if false { + } else { + *((*int32)(x.Replicas)) = int32(r.DecodeInt(32)) + } + } + case "selector": + if r.TryDecodeAsNil() { + if x.Selector != nil { + x.Selector = nil + } + } else { + if x.Selector == nil { + x.Selector = new(pkg1_unversioned.LabelSelector) + } + yym7 := z.DecBinary() + _ = yym7 + if false { + } else if z.HasExtensions() && z.DecExt(x.Selector) { + } else { + z.DecFallback(x.Selector, false) + } + } + case "template": + if r.TryDecodeAsNil() { + x.Template = pkg2_v1.PodTemplateSpec{} + } else { + yyv8 := &x.Template + yyv8.CodecDecodeSelf(d) + } + case "volumeClaimTemplates": + if r.TryDecodeAsNil() { + x.VolumeClaimTemplates = nil + } else { + yyv9 := &x.VolumeClaimTemplates + yym10 := z.DecBinary() + _ = yym10 + if false { + } else { + h.decSlicev1_PersistentVolumeClaim((*[]pkg2_v1.PersistentVolumeClaim)(yyv9), d) + } + } + case "serviceName": + if r.TryDecodeAsNil() { + x.ServiceName = "" + } else { + x.ServiceName = string(r.DecodeString()) + } + default: + z.DecStructFieldNotFound(-1, yys3) + } // end switch yys3 + } // end for yyj3 + z.DecSendContainerState(codecSelfer_containerMapEnd1234) +} + +func (x *PetSetSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yyj12 int + var yyb12 bool + var yyhl12 bool = l >= 0 + yyj12++ + if yyhl12 { + yyb12 = yyj12 > l + } else { + yyb12 = r.CheckBreak() + } + if yyb12 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + if x.Replicas != nil { + x.Replicas = nil + } + } else { + if x.Replicas == nil { + x.Replicas = new(int32) + } + yym14 := z.DecBinary() + _ = yym14 + if false { + } else { + *((*int32)(x.Replicas)) = int32(r.DecodeInt(32)) + } + } + yyj12++ + if yyhl12 { + yyb12 = yyj12 > l + } else { + yyb12 = r.CheckBreak() + } + if yyb12 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + if x.Selector != nil { + x.Selector = nil + } + } else { + if x.Selector == nil { + x.Selector = new(pkg1_unversioned.LabelSelector) + } + yym16 := z.DecBinary() + _ = yym16 + if false { + } else if z.HasExtensions() && z.DecExt(x.Selector) { + } else { + z.DecFallback(x.Selector, false) + } + } + yyj12++ + if yyhl12 { + yyb12 = yyj12 > l + } else { + yyb12 = r.CheckBreak() + } + if yyb12 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Template = pkg2_v1.PodTemplateSpec{} + } else { + yyv17 := &x.Template + yyv17.CodecDecodeSelf(d) + } + yyj12++ + if yyhl12 { + yyb12 = yyj12 > l + } else { + yyb12 = r.CheckBreak() + } + if yyb12 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.VolumeClaimTemplates = nil + } else { + yyv18 := &x.VolumeClaimTemplates + yym19 := z.DecBinary() + _ = yym19 + if false { + } else { + h.decSlicev1_PersistentVolumeClaim((*[]pkg2_v1.PersistentVolumeClaim)(yyv18), d) + } + } + yyj12++ + if yyhl12 { + yyb12 = yyj12 > l + } else { + yyb12 = r.CheckBreak() + } + if yyb12 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.ServiceName = "" + } else { + x.ServiceName = string(r.DecodeString()) + } + for { + yyj12++ + if yyhl12 { + yyb12 = yyj12 > l + } else { + yyb12 = r.CheckBreak() + } + if yyb12 { + break + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + z.DecStructFieldNotFound(yyj12-1, "") + } + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x *PetSetStatus) CodecEncodeSelf(e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + if x == nil { + r.EncodeNil() + } else { + yym1 := z.EncBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.EncExt(x) { + } else { + yysep2 := !z.EncBinary() + yy2arr2 := z.EncBasicHandle().StructToArray + var yyq2 [2]bool + _, _, _ = yysep2, yyq2, yy2arr2 + const yyr2 bool = false + yyq2[0] = x.ObservedGeneration != nil + var yynn2 int + if yyr2 || yy2arr2 { + r.EncodeArrayStart(2) + } else { + yynn2 = 1 + for _, b := range yyq2 { + if b { + yynn2++ + } + } + r.EncodeMapStart(yynn2) + yynn2 = 0 + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[0] { + if x.ObservedGeneration == nil { + r.EncodeNil() + } else { + yy4 := *x.ObservedGeneration + yym5 := z.EncBinary() + _ = yym5 + if false { + } else { + r.EncodeInt(int64(yy4)) + } + } + } else { + r.EncodeNil() + } + } else { + if yyq2[0] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("observedGeneration")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + if x.ObservedGeneration == nil { + r.EncodeNil() + } else { + yy6 := *x.ObservedGeneration + yym7 := z.EncBinary() + _ = yym7 + if false { + } else { + r.EncodeInt(int64(yy6)) + } + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + yym9 := z.EncBinary() + _ = yym9 + if false { + } else { + r.EncodeInt(int64(x.Replicas)) + } + } else { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("replicas")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym10 := z.EncBinary() + _ = yym10 + if false { + } else { + r.EncodeInt(int64(x.Replicas)) + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + z.EncSendContainerState(codecSelfer_containerMapEnd1234) + } + } + } +} + +func (x *PetSetStatus) CodecDecodeSelf(d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + yym1 := z.DecBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.DecExt(x) { + } else { + yyct2 := r.ContainerType() + if yyct2 == codecSelferValueTypeMap1234 { + yyl2 := r.ReadMapStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerMapEnd1234) + } else { + x.codecDecodeSelfFromMap(yyl2, d) + } + } else if yyct2 == codecSelferValueTypeArray1234 { + yyl2 := r.ReadArrayStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + x.codecDecodeSelfFromArray(yyl2, d) + } + } else { + panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234) + } + } +} + +func (x *PetSetStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yys3Slc = z.DecScratchBuffer() // default slice to decode into + _ = yys3Slc + var yyhl3 bool = l >= 0 + for yyj3 := 0; ; yyj3++ { + if yyhl3 { + if yyj3 >= l { + break + } + } else { + if r.CheckBreak() { + break + } + } + z.DecSendContainerState(codecSelfer_containerMapKey1234) + yys3Slc = r.DecodeBytes(yys3Slc, true, true) + yys3 := string(yys3Slc) + z.DecSendContainerState(codecSelfer_containerMapValue1234) + switch yys3 { + case "observedGeneration": + if r.TryDecodeAsNil() { + if x.ObservedGeneration != nil { + x.ObservedGeneration = nil + } + } else { + if x.ObservedGeneration == nil { + x.ObservedGeneration = new(int64) + } + yym5 := z.DecBinary() + _ = yym5 + if false { + } else { + *((*int64)(x.ObservedGeneration)) = int64(r.DecodeInt(64)) + } + } + case "replicas": + if r.TryDecodeAsNil() { + x.Replicas = 0 + } else { + x.Replicas = int32(r.DecodeInt(32)) + } + default: + z.DecStructFieldNotFound(-1, yys3) + } // end switch yys3 + } // end for yyj3 + z.DecSendContainerState(codecSelfer_containerMapEnd1234) +} + +func (x *PetSetStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yyj7 int + var yyb7 bool + var yyhl7 bool = l >= 0 + yyj7++ + if yyhl7 { + yyb7 = yyj7 > l + } else { + yyb7 = r.CheckBreak() + } + if yyb7 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + if x.ObservedGeneration != nil { + x.ObservedGeneration = nil + } + } else { + if x.ObservedGeneration == nil { + x.ObservedGeneration = new(int64) + } + yym9 := z.DecBinary() + _ = yym9 + if false { + } else { + *((*int64)(x.ObservedGeneration)) = int64(r.DecodeInt(64)) + } + } + yyj7++ + if yyhl7 { + yyb7 = yyj7 > l + } else { + yyb7 = r.CheckBreak() + } + if yyb7 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Replicas = 0 + } else { + x.Replicas = int32(r.DecodeInt(32)) + } + for { + yyj7++ + if yyhl7 { + yyb7 = yyj7 > l + } else { + yyb7 = r.CheckBreak() + } + if yyb7 { + break + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + z.DecStructFieldNotFound(yyj7-1, "") + } + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x *PetSetList) CodecEncodeSelf(e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + if x == nil { + r.EncodeNil() + } else { + yym1 := z.EncBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.EncExt(x) { + } else { + yysep2 := !z.EncBinary() + yy2arr2 := z.EncBasicHandle().StructToArray + var yyq2 [4]bool + _, _, _ = yysep2, yyq2, yy2arr2 + const yyr2 bool = false + yyq2[0] = true + yyq2[2] = x.Kind != "" + yyq2[3] = x.APIVersion != "" + var yynn2 int + if yyr2 || yy2arr2 { + r.EncodeArrayStart(4) + } else { + yynn2 = 1 + for _, b := range yyq2 { + if b { + yynn2++ + } + } + r.EncodeMapStart(yynn2) + yynn2 = 0 + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[0] { + yy4 := &x.ListMeta + yym5 := z.EncBinary() + _ = yym5 + if false { + } else if z.HasExtensions() && z.EncExt(yy4) { + } else { + z.EncFallback(yy4) + } + } else { + r.EncodeNil() + } + } else { + if yyq2[0] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("metadata")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yy6 := &x.ListMeta + yym7 := z.EncBinary() + _ = yym7 + if false { + } else if z.HasExtensions() && z.EncExt(yy6) { + } else { + z.EncFallback(yy6) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if x.Items == nil { + r.EncodeNil() + } else { + yym9 := z.EncBinary() + _ = yym9 + if false { + } else { + h.encSlicePetSet(([]PetSet)(x.Items), e) + } + } + } else { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("items")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + if x.Items == nil { + r.EncodeNil() + } else { + yym10 := z.EncBinary() + _ = yym10 + if false { + } else { + h.encSlicePetSet(([]PetSet)(x.Items), e) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[2] { + yym12 := z.EncBinary() + _ = yym12 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.Kind)) + } + } else { + r.EncodeString(codecSelferC_UTF81234, "") + } + } else { + if yyq2[2] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("kind")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym13 := z.EncBinary() + _ = yym13 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.Kind)) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + if yyq2[3] { + yym15 := z.EncBinary() + _ = yym15 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion)) + } + } else { + r.EncodeString(codecSelferC_UTF81234, "") + } + } else { + if yyq2[3] { + z.EncSendContainerState(codecSelfer_containerMapKey1234) + r.EncodeString(codecSelferC_UTF81234, string("apiVersion")) + z.EncSendContainerState(codecSelfer_containerMapValue1234) + yym16 := z.EncBinary() + _ = yym16 + if false { + } else { + r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion)) + } + } + } + if yyr2 || yy2arr2 { + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + z.EncSendContainerState(codecSelfer_containerMapEnd1234) + } + } + } +} + +func (x *PetSetList) CodecDecodeSelf(d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + yym1 := z.DecBinary() + _ = yym1 + if false { + } else if z.HasExtensions() && z.DecExt(x) { + } else { + yyct2 := r.ContainerType() + if yyct2 == codecSelferValueTypeMap1234 { + yyl2 := r.ReadMapStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerMapEnd1234) + } else { + x.codecDecodeSelfFromMap(yyl2, d) + } + } else if yyct2 == codecSelferValueTypeArray1234 { + yyl2 := r.ReadArrayStart() + if yyl2 == 0 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + } else { + x.codecDecodeSelfFromArray(yyl2, d) + } + } else { + panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234) + } + } +} + +func (x *PetSetList) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yys3Slc = z.DecScratchBuffer() // default slice to decode into + _ = yys3Slc + var yyhl3 bool = l >= 0 + for yyj3 := 0; ; yyj3++ { + if yyhl3 { + if yyj3 >= l { + break + } + } else { + if r.CheckBreak() { + break + } + } + z.DecSendContainerState(codecSelfer_containerMapKey1234) + yys3Slc = r.DecodeBytes(yys3Slc, true, true) + yys3 := string(yys3Slc) + z.DecSendContainerState(codecSelfer_containerMapValue1234) + switch yys3 { + case "metadata": + if r.TryDecodeAsNil() { + x.ListMeta = pkg1_unversioned.ListMeta{} + } else { + yyv4 := &x.ListMeta + yym5 := z.DecBinary() + _ = yym5 + if false { + } else if z.HasExtensions() && z.DecExt(yyv4) { + } else { + z.DecFallback(yyv4, false) + } + } + case "items": + if r.TryDecodeAsNil() { + x.Items = nil + } else { + yyv6 := &x.Items + yym7 := z.DecBinary() + _ = yym7 + if false { + } else { + h.decSlicePetSet((*[]PetSet)(yyv6), d) + } + } + case "kind": + if r.TryDecodeAsNil() { + x.Kind = "" + } else { + x.Kind = string(r.DecodeString()) + } + case "apiVersion": + if r.TryDecodeAsNil() { + x.APIVersion = "" + } else { + x.APIVersion = string(r.DecodeString()) + } + default: + z.DecStructFieldNotFound(-1, yys3) + } // end switch yys3 + } // end for yyj3 + z.DecSendContainerState(codecSelfer_containerMapEnd1234) +} + +func (x *PetSetList) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + var yyj10 int + var yyb10 bool + var yyhl10 bool = l >= 0 + yyj10++ + if yyhl10 { + yyb10 = yyj10 > l + } else { + yyb10 = r.CheckBreak() + } + if yyb10 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.ListMeta = pkg1_unversioned.ListMeta{} + } else { + yyv11 := &x.ListMeta + yym12 := z.DecBinary() + _ = yym12 + if false { + } else if z.HasExtensions() && z.DecExt(yyv11) { + } else { + z.DecFallback(yyv11, false) + } + } + yyj10++ + if yyhl10 { + yyb10 = yyj10 > l + } else { + yyb10 = r.CheckBreak() + } + if yyb10 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Items = nil + } else { + yyv13 := &x.Items + yym14 := z.DecBinary() + _ = yym14 + if false { + } else { + h.decSlicePetSet((*[]PetSet)(yyv13), d) + } + } + yyj10++ + if yyhl10 { + yyb10 = yyj10 > l + } else { + yyb10 = r.CheckBreak() + } + if yyb10 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.Kind = "" + } else { + x.Kind = string(r.DecodeString()) + } + yyj10++ + if yyhl10 { + yyb10 = yyj10 > l + } else { + yyb10 = r.CheckBreak() + } + if yyb10 { + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) + return + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + if r.TryDecodeAsNil() { + x.APIVersion = "" + } else { + x.APIVersion = string(r.DecodeString()) + } + for { + yyj10++ + if yyhl10 { + yyb10 = yyj10 > l + } else { + yyb10 = r.CheckBreak() + } + if yyb10 { + break + } + z.DecSendContainerState(codecSelfer_containerArrayElem1234) + z.DecStructFieldNotFound(yyj10-1, "") + } + z.DecSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x codecSelfer1234) encSlicev1_PersistentVolumeClaim(v []pkg2_v1.PersistentVolumeClaim, e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + r.EncodeArrayStart(len(v)) + for _, yyv1 := range v { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + yy2 := &yyv1 + yy2.CodecEncodeSelf(e) + } + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x codecSelfer1234) decSlicev1_PersistentVolumeClaim(v *[]pkg2_v1.PersistentVolumeClaim, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + + yyv1 := *v + yyh1, yyl1 := z.DecSliceHelperStart() + var yyc1 bool + _ = yyc1 + if yyl1 == 0 { + if yyv1 == nil { + yyv1 = []pkg2_v1.PersistentVolumeClaim{} + yyc1 = true + } else if len(yyv1) != 0 { + yyv1 = yyv1[:0] + yyc1 = true + } + } else if yyl1 > 0 { + var yyrr1, yyrl1 int + var yyrt1 bool + _, _ = yyrl1, yyrt1 + yyrr1 = yyl1 // len(yyv1) + if yyl1 > cap(yyv1) { + + yyrg1 := len(yyv1) > 0 + yyv21 := yyv1 + yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 296) + if yyrt1 { + if yyrl1 <= cap(yyv1) { + yyv1 = yyv1[:yyrl1] + } else { + yyv1 = make([]pkg2_v1.PersistentVolumeClaim, yyrl1) + } + } else { + yyv1 = make([]pkg2_v1.PersistentVolumeClaim, yyrl1) + } + yyc1 = true + yyrr1 = len(yyv1) + if yyrg1 { + copy(yyv1, yyv21) + } + } else if yyl1 != len(yyv1) { + yyv1 = yyv1[:yyl1] + yyc1 = true + } + yyj1 := 0 + for ; yyj1 < yyrr1; yyj1++ { + yyh1.ElemContainerState(yyj1) + if r.TryDecodeAsNil() { + yyv1[yyj1] = pkg2_v1.PersistentVolumeClaim{} + } else { + yyv2 := &yyv1[yyj1] + yyv2.CodecDecodeSelf(d) + } + + } + if yyrt1 { + for ; yyj1 < yyl1; yyj1++ { + yyv1 = append(yyv1, pkg2_v1.PersistentVolumeClaim{}) + yyh1.ElemContainerState(yyj1) + if r.TryDecodeAsNil() { + yyv1[yyj1] = pkg2_v1.PersistentVolumeClaim{} + } else { + yyv3 := &yyv1[yyj1] + yyv3.CodecDecodeSelf(d) + } + + } + } + + } else { + yyj1 := 0 + for ; !r.CheckBreak(); yyj1++ { + + if yyj1 >= len(yyv1) { + yyv1 = append(yyv1, pkg2_v1.PersistentVolumeClaim{}) // var yyz1 pkg2_v1.PersistentVolumeClaim + yyc1 = true + } + yyh1.ElemContainerState(yyj1) + if yyj1 < len(yyv1) { + if r.TryDecodeAsNil() { + yyv1[yyj1] = pkg2_v1.PersistentVolumeClaim{} + } else { + yyv4 := &yyv1[yyj1] + yyv4.CodecDecodeSelf(d) + } + + } else { + z.DecSwallow() + } + + } + if yyj1 < len(yyv1) { + yyv1 = yyv1[:yyj1] + yyc1 = true + } else if yyj1 == 0 && yyv1 == nil { + yyv1 = []pkg2_v1.PersistentVolumeClaim{} + yyc1 = true + } + } + yyh1.End() + if yyc1 { + *v = yyv1 + } +} + +func (x codecSelfer1234) encSlicePetSet(v []PetSet, e *codec1978.Encoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperEncoder(e) + _, _, _ = h, z, r + r.EncodeArrayStart(len(v)) + for _, yyv1 := range v { + z.EncSendContainerState(codecSelfer_containerArrayElem1234) + yy2 := &yyv1 + yy2.CodecEncodeSelf(e) + } + z.EncSendContainerState(codecSelfer_containerArrayEnd1234) +} + +func (x codecSelfer1234) decSlicePetSet(v *[]PetSet, d *codec1978.Decoder) { + var h codecSelfer1234 + z, r := codec1978.GenHelperDecoder(d) + _, _, _ = h, z, r + + yyv1 := *v + yyh1, yyl1 := z.DecSliceHelperStart() + var yyc1 bool + _ = yyc1 + if yyl1 == 0 { + if yyv1 == nil { + yyv1 = []PetSet{} + yyc1 = true + } else if len(yyv1) != 0 { + yyv1 = yyv1[:0] + yyc1 = true + } + } else if yyl1 > 0 { + var yyrr1, yyrl1 int + var yyrt1 bool + _, _ = yyrl1, yyrt1 + yyrr1 = yyl1 // len(yyv1) + if yyl1 > cap(yyv1) { + + yyrg1 := len(yyv1) > 0 + yyv21 := yyv1 + yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 616) + if yyrt1 { + if yyrl1 <= cap(yyv1) { + yyv1 = yyv1[:yyrl1] + } else { + yyv1 = make([]PetSet, yyrl1) + } + } else { + yyv1 = make([]PetSet, yyrl1) + } + yyc1 = true + yyrr1 = len(yyv1) + if yyrg1 { + copy(yyv1, yyv21) + } + } else if yyl1 != len(yyv1) { + yyv1 = yyv1[:yyl1] + yyc1 = true + } + yyj1 := 0 + for ; yyj1 < yyrr1; yyj1++ { + yyh1.ElemContainerState(yyj1) + if r.TryDecodeAsNil() { + yyv1[yyj1] = PetSet{} + } else { + yyv2 := &yyv1[yyj1] + yyv2.CodecDecodeSelf(d) + } + + } + if yyrt1 { + for ; yyj1 < yyl1; yyj1++ { + yyv1 = append(yyv1, PetSet{}) + yyh1.ElemContainerState(yyj1) + if r.TryDecodeAsNil() { + yyv1[yyj1] = PetSet{} + } else { + yyv3 := &yyv1[yyj1] + yyv3.CodecDecodeSelf(d) + } + + } + } + + } else { + yyj1 := 0 + for ; !r.CheckBreak(); yyj1++ { + + if yyj1 >= len(yyv1) { + yyv1 = append(yyv1, PetSet{}) // var yyz1 PetSet + yyc1 = true + } + yyh1.ElemContainerState(yyj1) + if yyj1 < len(yyv1) { + if r.TryDecodeAsNil() { + yyv1[yyj1] = PetSet{} + } else { + yyv4 := &yyv1[yyj1] + yyv4.CodecDecodeSelf(d) + } + + } else { + z.DecSwallow() + } + + } + if yyj1 < len(yyv1) { + yyv1 = yyv1[:yyj1] + yyc1 = true + } else if yyj1 == 0 && yyv1 == nil { + yyv1 = []PetSet{} + yyc1 = true + } + } + yyh1.End() + if yyc1 { + *v = yyv1 + } +} diff --git a/pkg/apis/apps/v1alpha1/types.go b/pkg/apis/apps/v1alpha1/types.go new file mode 100644 index 00000000000..5306483ab4b --- /dev/null +++ b/pkg/apis/apps/v1alpha1/types.go @@ -0,0 +1,94 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 v1alpha1 + +import ( + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/api/v1" +) + +// PetSet represents a set of pods with consistent identities. +// Identities are defined as: +// - Network: A single stable DNS and hostname. +// - Storage: As many VolumeClaims as requested. +// The PetSet guarantees that a given network identity will always +// map to the same storage identity. PetSet is currently in alpha +// and subject to change without notice. +type PetSet struct { + unversioned.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Spec defines the desired identities of pets in this set. + Spec PetSetSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` + + // Status is the current status of Pets in this PetSet. This data + // may be out of date by some window of time. + Status PetSetStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` +} + +// A PetSetSpec is the specification of a PetSet. +type PetSetSpec struct { + // Replicas is the desired number of replicas of the given Template. + // These are replicas in the sense that they are instantiations of the + // same Template, but individual replicas also have a consistent identity. + // If unspecified, defaults to 1. + // TODO: Consider a rename of this field. + Replicas *int32 `json:"replicas,omitempty" protobuf:"varint,1,opt,name=replicas"` + + // Selector is a label query over pods that should match the replica count. + // If empty, defaulted to labels on the pod template. + // More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors + Selector *unversioned.LabelSelector `json:"selector,omitempty" protobuf:"bytes,2,opt,name=selector"` + + // Template is the object that describes the pod that will be created if + // insufficient replicas are detected. Each pod stamped out by the PetSet + // will fulfill this Template, but have a unique identity from the rest + // of the PetSet. + Template v1.PodTemplateSpec `json:"template" protobuf:"bytes,3,opt,name=template"` + + // VolumeClaimTemplates is a list of claims that pets are allowed to reference. + // The PetSet controller is responsible for mapping network identities to + // claims in a way that maintains the identity of a pet. Every claim in + // this list must have at least one matching (by name) volumeMount in one + // container in the template. A claim in this list takes precedence over + // any volumes in the template, with the same name. + // TODO: Define the behavior if a claim already exists with the same name. + VolumeClaimTemplates []v1.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty" protobuf:"bytes,4,rep,name=volumeClaimTemplates"` + + // ServiceName is the name of the service that governs this PetSet. + // This service must exist before the PetSet, and is responsible for + // the network identity of the set. Pets get DNS/hostnames that follow the + // pattern: pet-specific-string.serviceName.default.svc.cluster.local + // where "pet-specific-string" is managed by the PetSet controller. + ServiceName string `json:"serviceName" protobuf:"bytes,5,opt,name=serviceName"` +} + +// PetSetStatus represents the current state of a PetSet. +type PetSetStatus struct { + // most recent generation observed by this autoscaler. + ObservedGeneration *int64 `json:"observedGeneration,omitempty" protobuf:"varint,1,opt,name=observedGeneration"` + + // Replicas is the number of actual replicas. + Replicas int32 `json:"replicas" protobuf:"varint,2,opt,name=replicas"` +} + +// PetSetList is a collection of PetSets. +type PetSetList struct { + unversioned.TypeMeta `json:",inline"` + unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + Items []PetSet `json:"items" protobuf:"bytes,2,rep,name=items"` +} diff --git a/pkg/apis/apps/v1alpha1/types_swagger_doc_generated.go b/pkg/apis/apps/v1alpha1/types_swagger_doc_generated.go new file mode 100644 index 00000000000..04b340c54bd --- /dev/null +++ b/pkg/apis/apps/v1alpha1/types_swagger_doc_generated.go @@ -0,0 +1,71 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +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 v1alpha1 + +// This file contains a collection of methods that can be used from go-restful to +// generate Swagger API documentation for its models. Please read this PR for more +// information on the implementation: https://github.com/emicklei/go-restful/pull/215 +// +// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if +// they are on one line! For multiple line or blocks that you want to ignore use ---. +// Any context after a --- is ignored. +// +// Those methods can be generated by using hack/update-generated-swagger-docs.sh + +// AUTO-GENERATED FUNCTIONS START HERE +var map_PetSet = map[string]string{ + "": "PetSet represents a set of pods with consistent identities. Identities are defined as:\n - Network: A single stable DNS and hostname.\n - Storage: As many VolumeClaims as requested.\nThe PetSet guarantees that a given network identity will always map to the same storage identity. PetSet is currently in alpha and subject to change without notice.", + "spec": "Spec defines the desired identities of pets in this set.", + "status": "Status is the current status of Pets in this PetSet. This data may be out of date by some window of time.", +} + +func (PetSet) SwaggerDoc() map[string]string { + return map_PetSet +} + +var map_PetSetList = map[string]string{ + "": "PetSetList is a collection of PetSets.", +} + +func (PetSetList) SwaggerDoc() map[string]string { + return map_PetSetList +} + +var map_PetSetSpec = map[string]string{ + "": "A PetSetSpec is the specification of a PetSet.", + "replicas": "Replicas is the desired number of replicas of the given Template. These are replicas in the sense that they are instantiations of the same Template, but individual replicas also have a consistent identity. If unspecified, defaults to 1.", + "selector": "Selector is a label query over pods that should match the replica count. If empty, defaulted to labels on the pod template. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors", + "template": "Template is the object that describes the pod that will be created if insufficient replicas are detected. Each pod stamped out by the PetSet will fulfill this Template, but have a unique identity from the rest of the PetSet.", + "volumeClaimTemplates": "VolumeClaimTemplates is a list of claims that pets are allowed to reference. The PetSet controller is responsible for mapping network identities to claims in a way that maintains the identity of a pet. Every claim in this list must have at least one matching (by name) volumeMount in one container in the template. A claim in this list takes precedence over any volumes in the template, with the same name.", + "serviceName": "ServiceName is the name of the service that governs this PetSet. This service must exist before the PetSet, and is responsible for the network identity of the set. Pets get DNS/hostnames that follow the pattern: pet-specific-string.serviceName.default.svc.cluster.local where \"pet-specific-string\" is managed by the PetSet controller.", +} + +func (PetSetSpec) SwaggerDoc() map[string]string { + return map_PetSetSpec +} + +var map_PetSetStatus = map[string]string{ + "": "PetSetStatus represents the current state of a PetSet.", + "observedGeneration": "most recent generation observed by this autoscaler.", + "replicas": "Replicas is the number of actual replicas.", +} + +func (PetSetStatus) SwaggerDoc() map[string]string { + return map_PetSetStatus +} + +// AUTO-GENERATED FUNCTIONS END HERE diff --git a/pkg/apis/apps/validation/validation.go b/pkg/apis/apps/validation/validation.go new file mode 100644 index 00000000000..fe66e289d7a --- /dev/null +++ b/pkg/apis/apps/validation/validation.go @@ -0,0 +1,110 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 validation + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + unversionedvalidation "k8s.io/kubernetes/pkg/api/unversioned/validation" + apivalidation "k8s.io/kubernetes/pkg/api/validation" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/util/validation/field" +) + +// ValidatePetSetName can be used to check whether the given PetSet +// name is valid. +// Prefix indicates this name will be used as part of generation, in which case +// trailing dashes are allowed. +func ValidatePetSetName(name string, prefix bool) (bool, string) { + return apivalidation.NameIsDNSSubdomain(name, prefix) +} + +// Validates the given template and ensures that it is in accordance with the desired selector. +func ValidatePodTemplateSpecForPetSet(template *api.PodTemplateSpec, selector labels.Selector, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if template == nil { + allErrs = append(allErrs, field.Required(fldPath, "")) + } else { + if !selector.Empty() { + // Verify that the PetSet selector matches the labels in template. + labels := labels.Set(template.Labels) + if !selector.Matches(labels) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata", "labels"), template.Labels, "`selector` does not match template `labels`")) + } + } + // TODO: Add validation for PodSpec, currently this will check volumes, which we know will + // fail. We should really check that the union of the given volumes and volumeClaims match + // volume mounts in the containers. + // allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(template, fldPath)...) + allErrs = append(allErrs, apivalidation.ValidateLabels(template.Labels, fldPath.Child("labels"))...) + allErrs = append(allErrs, apivalidation.ValidateAnnotations(template.Annotations, fldPath.Child("annotations"))...) + allErrs = append(allErrs, apivalidation.ValidatePodSpecificAnnotations(template.Annotations, fldPath.Child("annotations"))...) + } + return allErrs +} + +// ValidatePetSetSpec tests if required fields in the PetSet spec are set. +func ValidatePetSetSpec(spec *apps.PetSetSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...) + if spec.Selector == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("selector"), "")) + } else { + allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) + if len(spec.Selector.MatchLabels)+len(spec.Selector.MatchExpressions) == 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "empty selector is not valid for petset.")) + } + } + + selector, err := unversioned.LabelSelectorAsSelector(spec.Selector) + if err != nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "")) + } else { + allErrs = append(allErrs, ValidatePodTemplateSpecForPetSet(&spec.Template, selector, fldPath.Child("template"))...) + } + + if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"), spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)})) + } + + return allErrs +} + +// ValidatePetSet validates a PetSet. +func ValidatePetSet(petSet *apps.PetSet) field.ErrorList { + allErrs := apivalidation.ValidateObjectMeta(&petSet.ObjectMeta, true, ValidatePetSetName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidatePetSetSpec(&petSet.Spec, field.NewPath("spec"))...) + return allErrs +} + +// ValidatePetSetUpdate tests if required fields in the PetSet are set. +func ValidatePetSetUpdate(petSet, oldPetSet *apps.PetSet) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&petSet.ObjectMeta, &oldPetSet.ObjectMeta, field.NewPath("metadata"))...) + allErrs = append(allErrs, ValidatePetSetSpec(&petSet.Spec, field.NewPath("spec"))...) + return allErrs +} + +// ValidatePetSetStatusUpdate tests if required fields in the PetSet are set. +func ValidatePetSetStatusUpdate(petSet, oldPetSet *apps.PetSet) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&petSet.ObjectMeta, &oldPetSet.ObjectMeta, field.NewPath("metadata"))...) + // TODO: Validate status. + return allErrs +} diff --git a/pkg/apis/apps/validation/validation_test.go b/pkg/apis/apps/validation/validation_test.go new file mode 100644 index 00000000000..1deaab8aaa1 --- /dev/null +++ b/pkg/apis/apps/validation/validation_test.go @@ -0,0 +1,379 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 validation + +import ( + "strings" + "testing" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/apps" +) + +func TestValidatePetSet(t *testing.T) { + validLabels := map[string]string{"a": "b"} + validPodTemplate := api.PodTemplate{ + Template: api.PodTemplateSpec{ + ObjectMeta: api.ObjectMeta{ + Labels: validLabels, + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + }, + }, + } + invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"} + invalidPodTemplate := api.PodTemplate{ + Template: api.PodTemplateSpec{ + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + }, + ObjectMeta: api.ObjectMeta{ + Labels: invalidLabels, + }, + }, + } + successCases := []apps.PetSet{ + { + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + { + ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + } + for _, successCase := range successCases { + if errs := ValidatePetSet(&successCase); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + } + + errorCases := map[string]apps.PetSet{ + "zero-length ID": { + ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + "missing-namespace": { + ObjectMeta: api.ObjectMeta{Name: "abc-123"}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + "empty selector": { + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Template: validPodTemplate.Template, + }, + }, + "selector_doesnt_match": { + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, + Template: validPodTemplate.Template, + }, + }, + "invalid manifest": { + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + }, + }, + "negative_replicas": { + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Replicas: -1, + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + }, + }, + "invalid_label": { + ObjectMeta: api.ObjectMeta{ + Name: "abc-123", + Namespace: api.NamespaceDefault, + Labels: map[string]string{ + "NoUppercaseOrSpecialCharsLike=Equals": "bar", + }, + }, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + "invalid_label 2": { + ObjectMeta: api.ObjectMeta{ + Name: "abc-123", + Namespace: api.NamespaceDefault, + Labels: map[string]string{ + "NoUppercaseOrSpecialCharsLike=Equals": "bar", + }, + }, + Spec: apps.PetSetSpec{ + Template: invalidPodTemplate.Template, + }, + }, + "invalid_annotation": { + ObjectMeta: api.ObjectMeta{ + Name: "abc-123", + Namespace: api.NamespaceDefault, + Annotations: map[string]string{ + "NoUppercaseOrSpecialCharsLike=Equals": "bar", + }, + }, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + "invalid restart policy 1": { + ObjectMeta: api.ObjectMeta{ + Name: "abc-123", + Namespace: api.NamespaceDefault, + }, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: api.PodTemplateSpec{ + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyOnFailure, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + }, + ObjectMeta: api.ObjectMeta{ + Labels: validLabels, + }, + }, + }, + }, + "invalid restart policy 2": { + ObjectMeta: api.ObjectMeta{ + Name: "abc-123", + Namespace: api.NamespaceDefault, + }, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: api.PodTemplateSpec{ + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyNever, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + }, + ObjectMeta: api.ObjectMeta{ + Labels: validLabels, + }, + }, + }, + }, + } + for k, v := range errorCases { + errs := ValidatePetSet(&v) + if len(errs) == 0 { + t.Errorf("expected failure for %s", k) + } + for i := range errs { + field := errs[i].Field + if !strings.HasPrefix(field, "spec.template.") && + field != "metadata.name" && + field != "metadata.namespace" && + field != "spec.selector" && + field != "spec.template" && + field != "GCEPersistentDisk.ReadOnly" && + field != "spec.replicas" && + field != "spec.template.labels" && + field != "metadata.annotations" && + field != "metadata.labels" && + field != "status.replicas" { + t.Errorf("%s: missing prefix for: %v", k, errs[i]) + } + } + } +} + +func TestValidatePetSetUpdate(t *testing.T) { + validLabels := map[string]string{"a": "b"} + validPodTemplate := api.PodTemplate{ + Template: api.PodTemplateSpec{ + ObjectMeta: api.ObjectMeta{ + Labels: validLabels, + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + }, + }, + } + readWriteVolumePodTemplate := api.PodTemplate{ + Template: api.PodTemplateSpec{ + ObjectMeta: api.ObjectMeta{ + Labels: validLabels, + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}}, + }, + }, + } + invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"} + invalidPodTemplate := api.PodTemplate{ + Template: api.PodTemplateSpec{ + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + }, + ObjectMeta: api.ObjectMeta{ + Labels: invalidLabels, + }, + }, + } + type psUpdateTest struct { + old apps.PetSet + update apps.PetSet + } + successCases := []psUpdateTest{ + { + old: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + update: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Replicas: 3, + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + }, + { + old: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + update: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Replicas: 1, + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: readWriteVolumePodTemplate.Template, + }, + }, + }, + } + for _, successCase := range successCases { + successCase.old.ObjectMeta.ResourceVersion = "1" + successCase.update.ObjectMeta.ResourceVersion = "1" + if errs := ValidatePetSetUpdate(&successCase.update, &successCase.old); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + } + errorCases := map[string]psUpdateTest{ + "more than one read/write": { + old: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + update: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Replicas: 2, + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: readWriteVolumePodTemplate.Template, + }, + }, + }, + "invalid selector": { + old: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + update: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Replicas: 2, + Selector: &unversioned.LabelSelector{MatchLabels: invalidLabels}, + Template: validPodTemplate.Template, + }, + }, + }, + "invalid pod": { + old: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + update: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Replicas: 2, + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: invalidPodTemplate.Template, + }, + }, + }, + "negative replicas": { + old: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + update: apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Replicas: -1, + Selector: &unversioned.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + }, + }, + }, + } + for testName, errorCase := range errorCases { + if errs := ValidatePetSetUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 { + t.Errorf("expected failure: %s", testName) + } + } +} diff --git a/pkg/client/clientset_generated/internalclientset/import_known_versions.go b/pkg/client/clientset_generated/internalclientset/import_known_versions.go index a74dbc5d27c..291037d5232 100644 --- a/pkg/client/clientset_generated/internalclientset/import_known_versions.go +++ b/pkg/client/clientset_generated/internalclientset/import_known_versions.go @@ -22,6 +22,7 @@ import ( _ "k8s.io/kubernetes/pkg/api/install" "k8s.io/kubernetes/pkg/apimachinery/registered" + _ "k8s.io/kubernetes/pkg/apis/apps/install" _ "k8s.io/kubernetes/pkg/apis/authorization/install" _ "k8s.io/kubernetes/pkg/apis/autoscaling/install" _ "k8s.io/kubernetes/pkg/apis/batch/install" diff --git a/pkg/client/unversioned/apps.go b/pkg/client/unversioned/apps.go new file mode 100644 index 00000000000..a6612d75a93 --- /dev/null +++ b/pkg/client/unversioned/apps.go @@ -0,0 +1,82 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/client/restclient" +) + +type AppsInterface interface { + PetSetNamespacer +} + +// AppsClient is used to interact with Kubernetes batch features. +type AppsClient struct { + *restclient.RESTClient +} + +func (c *AppsClient) PetSet(namespace string) PetSetInterface { + return newPetSet(c, namespace) +} + +func NewApps(c *restclient.Config) (*AppsClient, error) { + config := *c + if err := setAppsDefaults(&config); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &AppsClient{client}, nil +} + +func NewAppsOrDie(c *restclient.Config) *AppsClient { + client, err := NewApps(c) + if err != nil { + panic(err) + } + return client +} + +func setAppsDefaults(config *restclient.Config) error { + g, err := registered.Group(apps.GroupName) + if err != nil { + return err + } + config.APIPath = defaultAPIPath + if config.UserAgent == "" { + config.UserAgent = restclient.DefaultKubernetesUserAgent() + } + // TODO: Unconditionally set the config.Version, until we fix the config. + //if config.Version == "" { + copyGroupVersion := g.GroupVersion + config.GroupVersion = ©GroupVersion + //} + + config.Codec = api.Codecs.LegacyCodec(*config.GroupVersion) + if config.QPS == 0 { + config.QPS = 5 + } + if config.Burst == 0 { + config.Burst = 10 + } + return nil +} diff --git a/pkg/client/unversioned/client.go b/pkg/client/unversioned/client.go index b897bc230c7..f81b41d56a7 100644 --- a/pkg/client/unversioned/client.go +++ b/pkg/client/unversioned/client.go @@ -119,6 +119,7 @@ type Client struct { *AutoscalingClient *BatchClient *ExtensionsClient + *AppsClient *discovery.DiscoveryClient } @@ -156,6 +157,10 @@ func (c *Client) Extensions() ExtensionsInterface { return c.ExtensionsClient } +func (c *Client) Apps() AppsInterface { + return c.AppsClient +} + func (c *Client) Discovery() discovery.DiscoveryInterface { return c.DiscoveryClient } diff --git a/pkg/client/unversioned/helper.go b/pkg/client/unversioned/helper.go index 953b57463a6..46232bdc12c 100644 --- a/pkg/client/unversioned/helper.go +++ b/pkg/client/unversioned/helper.go @@ -22,6 +22,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" @@ -82,8 +83,16 @@ func New(c *restclient.Config) (*Client, error) { return nil, err } } + var appsClient *AppsClient + if registered.IsRegistered(apps.GroupName) { + appsConfig := *c + appsClient, err = NewApps(&appsConfig) + if err != nil { + return nil, err + } + } - return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, BatchClient: batchClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient}, nil + return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, BatchClient: batchClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient, AppsClient: appsClient}, nil } // MatchesServerVersion queries the server to compares the build version diff --git a/pkg/client/unversioned/import_known_versions.go b/pkg/client/unversioned/import_known_versions.go index c2d7fde2fb7..31a6710ccdb 100644 --- a/pkg/client/unversioned/import_known_versions.go +++ b/pkg/client/unversioned/import_known_versions.go @@ -22,6 +22,7 @@ import ( _ "k8s.io/kubernetes/pkg/api/install" "k8s.io/kubernetes/pkg/apimachinery/registered" + _ "k8s.io/kubernetes/pkg/apis/apps/install" _ "k8s.io/kubernetes/pkg/apis/authorization/install" _ "k8s.io/kubernetes/pkg/apis/autoscaling/install" _ "k8s.io/kubernetes/pkg/apis/batch/install" diff --git a/pkg/client/unversioned/pet_sets.go b/pkg/client/unversioned/pet_sets.go new file mode 100644 index 00000000000..e1897c28164 --- /dev/null +++ b/pkg/client/unversioned/pet_sets.go @@ -0,0 +1,100 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/watch" +) + +// PetSetNamespacer has methods to work with PetSet resources in a namespace +type PetSetNamespacer interface { + PetSet(namespace string) PetSetInterface +} + +// PetSetInterface exposes methods to work on PetSet resources. +type PetSetInterface interface { + List(opts api.ListOptions) (*apps.PetSetList, error) + Get(name string) (*apps.PetSet, error) + Create(petSet *apps.PetSet) (*apps.PetSet, error) + Update(petSet *apps.PetSet) (*apps.PetSet, error) + Delete(name string, options *api.DeleteOptions) error + Watch(opts api.ListOptions) (watch.Interface, error) + UpdateStatus(petSet *apps.PetSet) (*apps.PetSet, error) +} + +// petSet implements PetSetNamespacer interface +type petSet struct { + r *AppsClient + ns string +} + +// newPetSet returns a petSet +func newPetSet(c *AppsClient, namespace string) *petSet { + return &petSet{c, namespace} +} + +// List returns a list of petSet that match the label and field selectors. +func (c *petSet) List(opts api.ListOptions) (result *apps.PetSetList, err error) { + result = &apps.PetSetList{} + err = c.r.Get().Namespace(c.ns).Resource("petsets").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular petSet. +func (c *petSet) Get(name string) (result *apps.PetSet, err error) { + result = &apps.PetSet{} + err = c.r.Get().Namespace(c.ns).Resource("petsets").Name(name).Do().Into(result) + return +} + +// Create creates a new petSet. +func (c *petSet) Create(petSet *apps.PetSet) (result *apps.PetSet, err error) { + result = &apps.PetSet{} + err = c.r.Post().Namespace(c.ns).Resource("petsets").Body(petSet).Do().Into(result) + return +} + +// Update updates an existing petSet. +func (c *petSet) Update(petSet *apps.PetSet) (result *apps.PetSet, err error) { + result = &apps.PetSet{} + err = c.r.Put().Namespace(c.ns).Resource("petsets").Name(petSet.Name).Body(petSet).Do().Into(result) + return +} + +// Delete deletes a petSet, returns error if one occurs. +func (c *petSet) Delete(name string, options *api.DeleteOptions) (err error) { + return c.r.Delete().Namespace(c.ns).Resource("petsets").Name(name).Body(options).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested petSet. +func (c *petSet) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("petsets"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// UpdateStatus takes the name of the petSet and the new status. Returns the server's representation of the petSet, and an error, if it occurs. +func (c *petSet) UpdateStatus(petSet *apps.PetSet) (result *apps.PetSet, err error) { + result = &apps.PetSet{} + err = c.r.Put().Namespace(c.ns).Resource("petsets").Name(petSet.Name).SubResource("status").Body(petSet).Do().Into(result) + return +} diff --git a/pkg/client/unversioned/pet_sets_test.go b/pkg/client/unversioned/pet_sets_test.go new file mode 100644 index 00000000000..40ff03323e5 --- /dev/null +++ b/pkg/client/unversioned/pet_sets_test.go @@ -0,0 +1,165 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 unversioned_test + +import ( + "testing" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/testapi" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/client/unversioned/testclient/simple" +) + +func getPetSetResourceName() string { + return "petsets" +} + +func TestListPetSets(t *testing.T) { + ns := api.NamespaceAll + c := &simple.Client{ + Request: simple.Request{ + Method: "GET", + Path: testapi.Apps.ResourcePath(getPetSetResourceName(), ns, ""), + }, + Response: simple.Response{StatusCode: 200, + Body: &apps.PetSetList{ + Items: []apps.PetSet{ + { + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: apps.PetSetSpec{ + Replicas: 2, + Template: api.PodTemplateSpec{}, + }, + }, + }, + }, + }, + } + receivedRSList, err := c.Setup(t).Apps().PetSet(ns).List(api.ListOptions{}) + c.Validate(t, receivedRSList, err) +} + +func TestGetPetSet(t *testing.T) { + ns := api.NamespaceDefault + c := &simple.Client{ + Request: simple.Request{Method: "GET", Path: testapi.Apps.ResourcePath(getPetSetResourceName(), ns, "foo"), Query: simple.BuildQueryValues(nil)}, + Response: simple.Response{ + StatusCode: 200, + Body: &apps.PetSet{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: apps.PetSetSpec{ + Replicas: 2, + Template: api.PodTemplateSpec{}, + }, + }, + }, + } + receivedRS, err := c.Setup(t).Apps().PetSet(ns).Get("foo") + c.Validate(t, receivedRS, err) +} + +func TestGetPetSetWithNoName(t *testing.T) { + ns := api.NamespaceDefault + c := &simple.Client{Error: true} + receivedPod, err := c.Setup(t).Apps().PetSet(ns).Get("") + if (err != nil) && (err.Error() != simple.NameRequiredError) { + t.Errorf("Expected error: %v, but got %v", simple.NameRequiredError, err) + } + + c.Validate(t, receivedPod, err) +} + +func TestUpdatePetSet(t *testing.T) { + ns := api.NamespaceDefault + requestRS := &apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}, + } + c := &simple.Client{ + Request: simple.Request{Method: "PUT", Path: testapi.Apps.ResourcePath(getPetSetResourceName(), ns, "foo"), Query: simple.BuildQueryValues(nil)}, + Response: simple.Response{ + StatusCode: 200, + Body: &apps.PetSet{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: apps.PetSetSpec{ + Replicas: 2, + Template: api.PodTemplateSpec{}, + }, + }, + }, + } + receivedRS, err := c.Setup(t).Apps().PetSet(ns).Update(requestRS) + c.Validate(t, receivedRS, err) +} + +func TestDeletePetSet(t *testing.T) { + ns := api.NamespaceDefault + c := &simple.Client{ + Request: simple.Request{Method: "DELETE", Path: testapi.Apps.ResourcePath(getPetSetResourceName(), ns, "foo"), Query: simple.BuildQueryValues(nil)}, + Response: simple.Response{StatusCode: 200}, + } + err := c.Setup(t).Apps().PetSet(ns).Delete("foo", nil) + c.Validate(t, nil, err) +} + +func TestCreatePetSet(t *testing.T) { + ns := api.NamespaceDefault + requestRS := &apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "foo"}, + } + c := &simple.Client{ + Request: simple.Request{Method: "POST", Path: testapi.Apps.ResourcePath(getPetSetResourceName(), ns, ""), Body: requestRS, Query: simple.BuildQueryValues(nil)}, + Response: simple.Response{ + StatusCode: 200, + Body: &apps.PetSet{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: apps.PetSetSpec{ + Replicas: 2, + Template: api.PodTemplateSpec{}, + }, + }, + }, + } + receivedRS, err := c.Setup(t).Apps().PetSet(ns).Create(requestRS) + c.Validate(t, receivedRS, err) +} + +// TODO: Test Status actions. diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index d04cc132c90..cd1eb110c38 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -41,6 +41,7 @@ import ( "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/apimachinery" "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" @@ -317,6 +318,8 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { return c.AutoscalingClient.RESTClient, nil case batch.GroupName: return c.BatchClient.RESTClient, nil + case apps.GroupName: + return c.AppsClient.RESTClient, nil case extensions.GroupName: return c.ExtensionsClient.RESTClient, nil case api.SchemeGroupVersion.Group: @@ -892,6 +895,13 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { } return getSchemaAndValidate(c.c.AutoscalingClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir) } + if gvk.Group == apps.GroupName { + if c.c.AppsClient == nil { + return errors.New("unable to validate: no autoscaling client") + } + return getSchemaAndValidate(c.c.AppsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir) + } + if gvk.Group == batch.GroupName { if c.c.BatchClient == nil { return errors.New("unable to validate: no batch client") diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index 32eaa2e163c..623bf6f2b62 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -35,6 +35,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/runtime" @@ -417,6 +418,7 @@ var replicaSetColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"} var jobColumns = []string{"NAME", "DESIRED", "SUCCESSFUL", "AGE"} var serviceColumns = []string{"NAME", "CLUSTER-IP", "EXTERNAL-IP", "PORT(S)", "AGE"} var ingressColumns = []string{"NAME", "RULE", "BACKEND", "ADDRESS", "AGE"} +var petSetColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"} var endpointColumns = []string{"NAME", "ENDPOINTS", "AGE"} var nodeColumns = []string{"NAME", "STATUS", "AGE"} var daemonSetColumns = []string{"NAME", "DESIRED", "CURRENT", "NODE-SELECTOR", "AGE"} @@ -457,6 +459,8 @@ func (h *HumanReadablePrinter) addDefaultHandlers() { h.Handler(serviceColumns, printServiceList) h.Handler(ingressColumns, printIngress) h.Handler(ingressColumns, printIngressList) + h.Handler(petSetColumns, printPetSet) + h.Handler(petSetColumns, printPetSetList) h.Handler(endpointColumns, printEndpoints) h.Handler(endpointColumns, printEndpointsList) h.Handler(nodeColumns, printNode) @@ -1015,6 +1019,53 @@ func printIngressList(ingressList *extensions.IngressList, w io.Writer, options return nil } +func printPetSet(ps *apps.PetSet, w io.Writer, options PrintOptions) error { + name := ps.Name + namespace := ps.Namespace + containers := ps.Spec.Template.Spec.Containers + + if options.WithNamespace { + if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { + return err + } + } + desiredReplicas := ps.Spec.Replicas + currentReplicas := ps.Status.Replicas + if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s", + name, + desiredReplicas, + currentReplicas, + translateTimestamp(ps.CreationTimestamp), + ); err != nil { + return err + } + if options.Wide { + if err := layoutContainers(containers, w); err != nil { + return err + } + if _, err := fmt.Fprintf(w, "\t%s", unversioned.FormatLabelSelector(ps.Spec.Selector)); err != nil { + return err + } + } + if _, err := fmt.Fprint(w, appendLabels(ps.Labels, options.ColumnLabels)); err != nil { + return err + } + if _, err := fmt.Fprint(w, appendAllLabels(options.ShowLabels, ps.Labels)); err != nil { + return err + } + + return nil +} + +func printPetSetList(petSetList *apps.PetSetList, w io.Writer, options PrintOptions) error { + for _, ps := range petSetList.Items { + if err := printPetSet(&ps, w, options); err != nil { + return err + } + } + return nil +} + func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options PrintOptions) error { name := ds.Name namespace := ds.Namespace diff --git a/pkg/master/import_known_versions.go b/pkg/master/import_known_versions.go index 30be6db5061..01a297e45a1 100644 --- a/pkg/master/import_known_versions.go +++ b/pkg/master/import_known_versions.go @@ -22,6 +22,7 @@ import ( _ "k8s.io/kubernetes/pkg/api/install" "k8s.io/kubernetes/pkg/apimachinery/registered" + _ "k8s.io/kubernetes/pkg/apis/apps/install" _ "k8s.io/kubernetes/pkg/apis/authorization/install" _ "k8s.io/kubernetes/pkg/apis/autoscaling/install" _ "k8s.io/kubernetes/pkg/apis/batch/install" diff --git a/pkg/master/master.go b/pkg/master/master.go index 20eecb5d271..35e18bd8b27 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -32,6 +32,8 @@ import ( "k8s.io/kubernetes/pkg/api/unversioned" apiv1 "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/apps" + appsapi "k8s.io/kubernetes/pkg/apis/apps/v1alpha1" "k8s.io/kubernetes/pkg/apis/autoscaling" autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1" "k8s.io/kubernetes/pkg/apis/batch" @@ -62,6 +64,7 @@ import ( nodeetcd "k8s.io/kubernetes/pkg/registry/node/etcd" pvetcd "k8s.io/kubernetes/pkg/registry/persistentvolume/etcd" pvcetcd "k8s.io/kubernetes/pkg/registry/persistentvolumeclaim/etcd" + petsetetcd "k8s.io/kubernetes/pkg/registry/petset/etcd" podetcd "k8s.io/kubernetes/pkg/registry/pod/etcd" pspetcd "k8s.io/kubernetes/pkg/registry/podsecuritypolicy/etcd" podtemplateetcd "k8s.io/kubernetes/pkg/registry/podtemplate/etcd" @@ -349,6 +352,38 @@ func (m *Master) InstallAPIs(c *Config) { allGroups = append(allGroups, group) } + if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(appsapi.SchemeGroupVersion) { + appsResources := m.getAppsResources(c) + appsGroupMeta := registered.GroupOrDie(apps.GroupName) + + // Hard code preferred group version to apps/v1alpha1 + appsGroupMeta.GroupVersion = appsapi.SchemeGroupVersion + + apiGroupInfo := genericapiserver.APIGroupInfo{ + GroupMeta: *appsGroupMeta, + VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ + "v1alpha1": appsResources, + }, + OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, + Scheme: api.Scheme, + ParameterCodec: api.ParameterCodec, + NegotiatedSerializer: api.Codecs, + NegotiatedStreamSerializer: api.StreamCodecs, + } + apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) + + appsGVForDiscovery := unversioned.GroupVersionForDiscovery{ + GroupVersion: appsGroupMeta.GroupVersion.String(), + Version: appsGroupMeta.GroupVersion.Version, + } + group := unversioned.APIGroup{ + Name: appsGroupMeta.GroupVersion.Group, + Versions: []unversioned.GroupVersionForDiscovery{appsGVForDiscovery}, + PreferredVersion: appsGVForDiscovery, + } + allGroups = append(allGroups, group) + + } if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } @@ -824,6 +859,27 @@ func (m *Master) getBatchResources(c *Config) map[string]rest.Storage { return storage } +// getPetSetResources returns the resources for batch api +func (m *Master) getAppsResources(c *Config) map[string]rest.Storage { + // TODO update when we support more than one version of this group + version := appsapi.SchemeGroupVersion + + storage := map[string]rest.Storage{} + if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("petsets")) { + restOptions := func(resource string) generic.RESTOptions { + return generic.RESTOptions{ + Storage: c.StorageDestinations.Get(apps.GroupName, resource), + Decorator: m.StorageDecorator(), + DeleteCollectionWorkers: m.deleteCollectionWorkers, + } + } + petsetStorage, petsetStatusStorage := petsetetcd.NewREST(restOptions("petsets")) + storage["petsets"] = petsetStorage + storage["petsets/status"] = petsetStatusStorage + } + return storage +} + // findExternalAddress returns ExternalIP of provided node with fallback to LegacyHostIP. func findExternalAddress(node *api.Node) (string, error) { var fallback string @@ -876,7 +932,7 @@ func (m *Master) IsTunnelSyncHealthy(req *http.Request) error { func DefaultAPIResourceConfigSource() *genericapiserver.ResourceConfig { ret := genericapiserver.NewResourceConfig() - ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion) + ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion, appsapi.SchemeGroupVersion) // all extensions resources except these are disabled by default ret.EnableResources( diff --git a/pkg/master/master_test.go b/pkg/master/master_test.go index 55189172c6e..87a93c5c30f 100644 --- a/pkg/master/master_test.go +++ b/pkg/master/master_test.go @@ -38,6 +38,8 @@ import ( apiutil "k8s.io/kubernetes/pkg/api/util" apiv1 "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/apis/apps" + appsapi "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/autoscaling" autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1" "k8s.io/kubernetes/pkg/apis/batch" @@ -78,6 +80,8 @@ func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert. autoscaling.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Autoscaling.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize)) storageDestinations.AddAPIGroup( batch.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Batch.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize)) + storageDestinations.AddAPIGroup( + apps.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Apps.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize)) storageDestinations.AddAPIGroup( extensions.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Extensions.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize)) @@ -85,6 +89,7 @@ func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert. storageVersions[api.GroupName] = testapi.Default.GroupVersion().String() storageVersions[autoscaling.GroupName] = testapi.Autoscaling.GroupVersion().String() storageVersions[batch.GroupName] = testapi.Batch.GroupVersion().String() + storageVersions[apps.GroupName] = testapi.Apps.GroupVersion().String() storageVersions[extensions.GroupName] = testapi.Extensions.GroupVersion().String() config.StorageVersions = storageVersions config.PublicAddress = net.ParseIP("192.168.10.4") @@ -123,7 +128,7 @@ func newMaster(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *ass // limitedAPIResourceConfigSource only enables the core group, the extensions group, the batch group, and the autoscaling group. func limitedAPIResourceConfigSource() *genericapiserver.ResourceConfig { ret := genericapiserver.NewResourceConfig() - ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion) + ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, appsapi.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion) return ret } @@ -410,7 +415,7 @@ func TestDiscoveryAtAPIS(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - expectGroupNames := sets.NewString(autoscaling.GroupName, batch.GroupName, extensions.GroupName) + expectGroupNames := sets.NewString(autoscaling.GroupName, batch.GroupName, apps.GroupName, extensions.GroupName) expectVersions := map[string][]unversioned.GroupVersionForDiscovery{ autoscaling.GroupName: { { @@ -424,6 +429,12 @@ func TestDiscoveryAtAPIS(t *testing.T) { Version: testapi.Batch.GroupVersion().Version, }, }, + apps.GroupName: { + { + GroupVersion: testapi.Apps.GroupVersion().String(), + Version: testapi.Apps.GroupVersion().Version, + }, + }, extensions.GroupName: { { GroupVersion: testapi.Extensions.GroupVersion().String(), @@ -440,6 +451,10 @@ func TestDiscoveryAtAPIS(t *testing.T) { GroupVersion: config.StorageVersions[batch.GroupName], Version: apiutil.GetVersion(config.StorageVersions[batch.GroupName]), }, + apps.GroupName: { + GroupVersion: config.StorageVersions[apps.GroupName], + Version: apiutil.GetVersion(config.StorageVersions[apps.GroupName]), + }, extensions.GroupName: { GroupVersion: config.StorageVersions[extensions.GroupName], Version: apiutil.GetVersion(config.StorageVersions[extensions.GroupName]), diff --git a/pkg/registry/cachesize/cachesize.go b/pkg/registry/cachesize/cachesize.go index 708a4441d21..048597babca 100644 --- a/pkg/registry/cachesize/cachesize.go +++ b/pkg/registry/cachesize/cachesize.go @@ -34,6 +34,7 @@ const ( Endpoints Resource = "endpoints" HorizontalPodAutoscalers Resource = "horizontalpodautoscalers" Ingress Resource = "ingress" + PetSet Resource = "petset" Jobs Resource = "jobs" LimitRanges Resource = "limitranges" Namespaces Resource = "namespaces" @@ -59,6 +60,7 @@ func init() { watchCacheSizes[Endpoints] = 1000 watchCacheSizes[HorizontalPodAutoscalers] = 100 watchCacheSizes[Ingress] = 100 + watchCacheSizes[PetSet] = 100 watchCacheSizes[Jobs] = 100 watchCacheSizes[LimitRanges] = 100 watchCacheSizes[Namespaces] = 100 diff --git a/pkg/registry/petset/doc.go b/pkg/registry/petset/doc.go new file mode 100644 index 00000000000..960710dd4f8 --- /dev/null +++ b/pkg/registry/petset/doc.go @@ -0,0 +1,17 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +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 petset diff --git a/pkg/registry/petset/etcd/etcd.go b/pkg/registry/petset/etcd/etcd.go new file mode 100644 index 00000000000..3d576136bc2 --- /dev/null +++ b/pkg/registry/petset/etcd/etcd.go @@ -0,0 +1,96 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +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 etcd + +import ( + "k8s.io/kubernetes/pkg/api" + appsapi "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/registry/cachesize" + "k8s.io/kubernetes/pkg/registry/generic" + etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd" + "k8s.io/kubernetes/pkg/registry/petset" + "k8s.io/kubernetes/pkg/runtime" +) + +// rest implements a RESTStorage for replication controllers against etcd +type REST struct { + *etcdgeneric.Etcd +} + +// NewREST returns a RESTStorage object that will work against replication controllers. +func NewREST(opts generic.RESTOptions) (*REST, *StatusREST) { + prefix := "/petsets" + + newListFunc := func() runtime.Object { return &appsapi.PetSetList{} } + storageInterface := opts.Decorator( + opts.Storage, cachesize.GetWatchCacheSizeByResource(cachesize.PetSet), &appsapi.PetSet{}, prefix, petset.Strategy, newListFunc) + + store := &etcdgeneric.Etcd{ + NewFunc: func() runtime.Object { return &appsapi.PetSet{} }, + + // NewListFunc returns an object capable of storing results of an etcd list. + NewListFunc: newListFunc, + // Produces a petSet that etcd understands, to the root of the resource + // by combining the namespace in the context with the given prefix + KeyRootFunc: func(ctx api.Context) string { + return etcdgeneric.NamespaceKeyRootFunc(ctx, prefix) + }, + // Produces a petSet that etcd understands, to the resource by combining + // the namespace in the context with the given prefix + KeyFunc: func(ctx api.Context, name string) (string, error) { + return etcdgeneric.NamespaceKeyFunc(ctx, prefix, name) + }, + // Retrieve the name field of a replication controller + ObjectNameFunc: func(obj runtime.Object) (string, error) { + return obj.(*appsapi.PetSet).Name, nil + }, + // Used to match objects based on labels/fields for list and watch + PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher { + return petset.MatchPetSet(label, field) + }, + QualifiedResource: appsapi.Resource("petsets"), + DeleteCollectionWorkers: opts.DeleteCollectionWorkers, + + // Used to validate controller creation + CreateStrategy: petset.Strategy, + + // Used to validate controller updates + UpdateStrategy: petset.Strategy, + DeleteStrategy: petset.Strategy, + + Storage: storageInterface, + } + statusStore := *store + statusStore.UpdateStrategy = petset.StatusStrategy + return &REST{store}, &StatusREST{store: &statusStore} +} + +// StatusREST implements the REST endpoint for changing the status of an petSet +type StatusREST struct { + store *etcdgeneric.Etcd +} + +func (r *StatusREST) New() runtime.Object { + return &appsapi.PetSet{} +} + +// Update alters the status subset of an object. +func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) { + return r.store.Update(ctx, obj) +} diff --git a/pkg/registry/petset/etcd/etcd_test.go b/pkg/registry/petset/etcd/etcd_test.go new file mode 100644 index 00000000000..678bc604b23 --- /dev/null +++ b/pkg/registry/petset/etcd/etcd_test.go @@ -0,0 +1,182 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 etcd + +import ( + "testing" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/registry/generic" + "k8s.io/kubernetes/pkg/registry/registrytest" + "k8s.io/kubernetes/pkg/storage/etcd/etcdtest" + etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" +) + +func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) { + etcdStorage, server := registrytest.NewEtcdStorage(t, apps.GroupName) + restOptions := generic.RESTOptions{Storage: etcdStorage, Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1} + petSetStorage, statusStorage := NewREST(restOptions) + return petSetStorage, statusStorage, server +} + +// createPetSet is a helper function that returns a PetSet with the updated resource version. +func createPetSet(storage *REST, ps apps.PetSet, t *testing.T) (apps.PetSet, error) { + ctx := api.WithNamespace(api.NewContext(), ps.Namespace) + obj, err := storage.Create(ctx, &ps) + if err != nil { + t.Errorf("Failed to create PetSet, %v", err) + } + newPS := obj.(*apps.PetSet) + return *newPS, nil +} + +func validNewPetSet() *apps.PetSet { + return &apps.PetSet{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: api.NamespaceDefault, + Labels: map[string]string{"a": "b"}, + }, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"a": "b"}}, + Template: api.PodTemplateSpec{ + ObjectMeta: api.ObjectMeta{ + Labels: map[string]string{"a": "b"}, + }, + Spec: api.PodSpec{ + Containers: []api.Container{ + { + Name: "test", + Image: "test_image", + ImagePullPolicy: api.PullIfNotPresent, + }, + }, + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + }, + }, + Replicas: 7, + }, + Status: apps.PetSetStatus{}, + } +} + +func TestCreate(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Etcd) + ps := validNewPetSet() + ps.ObjectMeta = api.ObjectMeta{} + test.TestCreate( + // valid + ps, + // TODO: Add an invalid case when we have validation. + ) +} + +// TODO: Test updates to spec when we allow them. + +func TestStatusUpdate(t *testing.T) { + storage, statusStorage, server := newStorage(t) + defer server.Terminate(t) + + ctx := api.WithNamespace(api.NewContext(), api.NamespaceDefault) + key := etcdtest.AddPrefix("/petsets/" + api.NamespaceDefault + "/foo") + validPetSet := validNewPetSet() + if err := storage.Storage.Create(ctx, key, validPetSet, nil, 0); err != nil { + t.Fatalf("unexpected error: %v", err) + } + update := apps.PetSet{ + ObjectMeta: validPetSet.ObjectMeta, + Spec: apps.PetSetSpec{ + Replicas: 7, + }, + Status: apps.PetSetStatus{ + Replicas: 7, + }, + } + + if _, _, err := statusStorage.Update(ctx, &update); err != nil { + t.Fatalf("unexpected error: %v", err) + } + obj, err := storage.Get(ctx, "foo") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + ps := obj.(*apps.PetSet) + if ps.Spec.Replicas != 7 { + t.Errorf("we expected .spec.replicas to not be updated but it was updated to %v", ps.Spec.Replicas) + } + if ps.Status.Replicas != 7 { + t.Errorf("we expected .status.replicas to be updated to %d but it was %v", 7, ps.Status.Replicas) + } +} + +func TestGet(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Etcd) + test.TestGet(validNewPetSet()) +} + +func TestList(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Etcd) + test.TestList(validNewPetSet()) +} + +func TestDelete(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Etcd) + test.TestDelete(validNewPetSet()) +} + +func TestWatch(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Etcd) + test.TestWatch( + validNewPetSet(), + // matching labels + []labels.Set{ + {"a": "b"}, + }, + // not matching labels + []labels.Set{ + {"a": "c"}, + {"foo": "bar"}, + }, + + // matching fields + []fields.Set{ + {"metadata.name": "foo"}, + }, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + }, + ) +} + +// TODO: Test generation number. diff --git a/pkg/registry/petset/strategy.go b/pkg/registry/petset/strategy.go new file mode 100644 index 00000000000..20a74c0174c --- /dev/null +++ b/pkg/registry/petset/strategy.go @@ -0,0 +1,142 @@ +/* +Copyright 2014 The Kubernetes Authors All rights reserved. + +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 petset + +import ( + "fmt" + "reflect" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/apis/apps/validation" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/registry/generic" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/util/validation/field" +) + +// petSetStrategy implements verification logic for Replication PetSets. +type petSetStrategy struct { + runtime.ObjectTyper + api.NameGenerator +} + +// Strategy is the default logic that applies when creating and updating Replication PetSet objects. +var Strategy = petSetStrategy{api.Scheme, api.SimpleNameGenerator} + +// NamespaceScoped returns true because all PetSet' need to be within a namespace. +func (petSetStrategy) NamespaceScoped() bool { + return true +} + +// PrepareForCreate clears the status of an PetSet before creation. +func (petSetStrategy) PrepareForCreate(obj runtime.Object) { + petSet := obj.(*apps.PetSet) + // create cannot set status + petSet.Status = apps.PetSetStatus{} + + petSet.Generation = 1 +} + +// PrepareForUpdate clears fields that are not allowed to be set by end users on update. +func (petSetStrategy) PrepareForUpdate(obj, old runtime.Object) { + newPetSet := obj.(*apps.PetSet) + oldPetSet := old.(*apps.PetSet) + // Update is not allowed to set status + newPetSet.Status = oldPetSet.Status + + // Any changes to the spec increment the generation number, any changes to the + // status should reflect the generation number of the corresponding object. + // See api.ObjectMeta description for more information on Generation. + if !reflect.DeepEqual(oldPetSet.Spec, newPetSet.Spec) { + newPetSet.Generation = oldPetSet.Generation + 1 + } + +} + +// Validate validates a new PetSet. +func (petSetStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { + petSet := obj.(*apps.PetSet) + return validation.ValidatePetSet(petSet) +} + +// Canonicalize normalizes the object after validation. +func (petSetStrategy) Canonicalize(obj runtime.Object) { +} + +// AllowCreateOnUpdate is false for PetSet; this means POST is needed to create one. +func (petSetStrategy) AllowCreateOnUpdate() bool { + return false +} + +// ValidateUpdate is the default update validation for an end user. +func (petSetStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { + return field.ErrorList{field.Forbidden(field.NewPath("spec"), "updates to petset spec are forbidden.")} + + // TODO: For now we're taking the safe route and disallowing all updates to spec. + // Enable on a case by case basis. + //validationErrorList := validation.ValidatePetSet(obj.(*apps.PetSet)) + //updateErrorList := validation.ValidatePetSetUpdate(obj.(*apps.PetSet), old.(*apps.PetSet)) + //return append(validationErrorList, updateErrorList...) +} + +// AllowUnconditionalUpdate is the default update policy for PetSet objects. +func (petSetStrategy) AllowUnconditionalUpdate() bool { + return true +} + +// PetSetToSelectableFields returns a field set that represents the object. +func PetSetToSelectableFields(petSet *apps.PetSet) fields.Set { + return generic.ObjectMetaFieldsSet(petSet.ObjectMeta, true) +} + +// MatchPetSet is the filter used by the generic etcd backend to watch events +// from etcd to clients of the apiserver only interested in specific labels/fields. +func MatchPetSet(label labels.Selector, field fields.Selector) generic.Matcher { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + petSet, ok := obj.(*apps.PetSet) + if !ok { + return nil, nil, fmt.Errorf("given object is not an PetSet.") + } + return labels.Set(petSet.ObjectMeta.Labels), PetSetToSelectableFields(petSet), nil + }, + } +} + +type petSetStatusStrategy struct { + petSetStrategy +} + +var StatusStrategy = petSetStatusStrategy{Strategy} + +// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status +func (petSetStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { + newPetSet := obj.(*apps.PetSet) + oldPetSet := old.(*apps.PetSet) + // status changes are not allowed to update spec + newPetSet.Spec = oldPetSet.Spec +} + +// ValidateUpdate is the default update validation for an end user updating status +func (petSetStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { + // TODO: Validate status updates. + return validation.ValidatePetSetStatusUpdate(obj.(*apps.PetSet), old.(*apps.PetSet)) +} diff --git a/pkg/registry/petset/strategy_test.go b/pkg/registry/petset/strategy_test.go new file mode 100644 index 00000000000..5869f4bdefb --- /dev/null +++ b/pkg/registry/petset/strategy_test.go @@ -0,0 +1,136 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 petset + +import ( + "testing" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/apps" +) + +func TestPetSetStrategy(t *testing.T) { + ctx := api.NewDefaultContext() + if !Strategy.NamespaceScoped() { + t.Errorf("PetSet must be namespace scoped") + } + if Strategy.AllowCreateOnUpdate() { + t.Errorf("PetSet should not allow create on update") + } + + validSelector := map[string]string{"a": "b"} + validPodTemplate := api.PodTemplate{ + Template: api.PodTemplateSpec{ + ObjectMeta: api.ObjectMeta{ + Labels: validSelector, + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + }, + }, + } + ps := &apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: apps.PetSetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validSelector}, + Template: validPodTemplate.Template, + }, + Status: apps.PetSetStatus{Replicas: 3}, + } + + Strategy.PrepareForCreate(ps) + if ps.Status.Replicas != 0 { + t.Error("PetSet should not allow setting status.pets on create") + } + errs := Strategy.Validate(ctx, ps) + if len(errs) != 0 { + t.Errorf("Unexpected error validating %v", errs) + } + + validPs := &apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: ps.Name, Namespace: ps.Namespace}, + Spec: apps.PetSetSpec{ + Selector: ps.Spec.Selector, + Template: validPodTemplate.Template, + }, + Status: apps.PetSetStatus{Replicas: 4}, + } + Strategy.PrepareForUpdate(validPs, ps) + errs = Strategy.ValidateUpdate(ctx, validPs, ps) + if len(errs) == 0 { + t.Errorf("Expected a validation error since updates are disallowed on petsets.") + } +} + +func TestPetSetStatusStrategy(t *testing.T) { + ctx := api.NewDefaultContext() + if !StatusStrategy.NamespaceScoped() { + t.Errorf("PetSet must be namespace scoped") + } + if StatusStrategy.AllowCreateOnUpdate() { + t.Errorf("PetSet should not allow create on update") + } + validSelector := map[string]string{"a": "b"} + validPodTemplate := api.PodTemplate{ + Template: api.PodTemplateSpec{ + ObjectMeta: api.ObjectMeta{ + Labels: validSelector, + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + }, + }, + } + oldPS := &apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault, ResourceVersion: "10"}, + Spec: apps.PetSetSpec{ + Replicas: 3, + Selector: &unversioned.LabelSelector{MatchLabels: validSelector}, + Template: validPodTemplate.Template, + }, + Status: apps.PetSetStatus{ + Replicas: 1, + }, + } + newPS := &apps.PetSet{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault, ResourceVersion: "9"}, + Spec: apps.PetSetSpec{ + Replicas: 1, + Selector: &unversioned.LabelSelector{MatchLabels: validSelector}, + Template: validPodTemplate.Template, + }, + Status: apps.PetSetStatus{ + Replicas: 2, + }, + } + StatusStrategy.PrepareForUpdate(newPS, oldPS) + if newPS.Status.Replicas != 2 { + t.Errorf("PetSet status updates should allow change of pets: %v", newPS.Status.Replicas) + } + if newPS.Spec.Replicas != 3 { + t.Errorf("PetSet status updates should not clobber spec: %v", newPS.Spec) + } + errs := StatusStrategy.ValidateUpdate(ctx, newPS, oldPS) + if len(errs) != 0 { + t.Errorf("Unexpected error %v", errs) + } +} diff --git a/test/integration/framework/etcd_utils.go b/test/integration/framework/etcd_utils.go index 7b638992c42..4cbd66b7e70 100644 --- a/test/integration/framework/etcd_utils.go +++ b/test/integration/framework/etcd_utils.go @@ -62,6 +62,13 @@ func NewBatchEtcdStorage(client etcd.Client) storage.Interface { return etcdstorage.NewEtcdStorage(client, testapi.Batch.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize) } +func NewAppsEtcdStorage(client etcd.Client) storage.Interface { + if client == nil { + client = NewEtcdClient() + } + return etcdstorage.NewEtcdStorage(client, testapi.Apps.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize) +} + func NewExtensionsEtcdStorage(client etcd.Client) storage.Interface { if client == nil { client = NewEtcdClient() diff --git a/test/integration/framework/master_utils.go b/test/integration/framework/master_utils.go index 07612882089..4e7b7381700 100644 --- a/test/integration/framework/master_utils.go +++ b/test/integration/framework/master_utils.go @@ -29,6 +29,7 @@ import ( "github.com/golang/glog" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" + "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" @@ -157,6 +158,8 @@ func NewMasterConfig() *master.Config { storageVersions[autoscaling.GroupName] = testapi.Autoscaling.GroupVersion().String() batchEtcdStorage := NewBatchEtcdStorage(etcdClient) storageVersions[batch.GroupName] = testapi.Batch.GroupVersion().String() + appsEtcdStorage := NewAppsEtcdStorage(etcdClient) + storageVersions[apps.GroupName] = testapi.Apps.GroupVersion().String() expEtcdStorage := NewExtensionsEtcdStorage(etcdClient) storageVersions[extensions.GroupName] = testapi.Extensions.GroupVersion().String() @@ -164,6 +167,7 @@ func NewMasterConfig() *master.Config { storageDestinations.AddAPIGroup(api.GroupName, etcdStorage) storageDestinations.AddAPIGroup(autoscaling.GroupName, autoscalingEtcdStorage) storageDestinations.AddAPIGroup(batch.GroupName, batchEtcdStorage) + storageDestinations.AddAPIGroup(apps.GroupName, appsEtcdStorage) storageDestinations.AddAPIGroup(extensions.GroupName, expEtcdStorage) return &master.Config{ diff --git a/test/integration/master_test.go b/test/integration/master_test.go index 8c62236d14a..bfffb136a01 100644 --- a/test/integration/master_test.go +++ b/test/integration/master_test.go @@ -55,6 +55,10 @@ func TestBatchPrefix(t *testing.T) { testPrefix(t, "/apis/batch/") } +func TestAppsPrefix(t *testing.T) { + testPrefix(t, "/apis/apps/") +} + func TestExtensionsPrefix(t *testing.T) { testPrefix(t, "/apis/extensions/") }