diff --git a/api/swagger-spec/policy.json b/api/swagger-spec/policy.json new file mode 100644 index 00000000000..e354660e72c --- /dev/null +++ b/api/swagger-spec/policy.json @@ -0,0 +1,110 @@ +{ + "swaggerVersion": "1.2", + "apiVersion": "", + "basePath": "https://10.10.10.10:443", + "resourcePath": "/apis/policy", + "apis": [ + { + "path": "/apis/policy", + "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/policy_v1alpha1.json b/api/swagger-spec/policy_v1alpha1.json new file mode 100644 index 00000000000..3091cd1ba1f --- /dev/null +++ b/api/swagger-spec/policy_v1alpha1.json @@ -0,0 +1,1315 @@ +{ + "swaggerVersion": "1.2", + "apiVersion": "policy/v1alpha1", + "basePath": "https://10.10.10.10:443", + "resourcePath": "/apis/policy/v1alpha1", + "apis": [ + { + "path": "/apis/policy/v1alpha1/namespaces/{namespace}/poddisruptionbudgets", + "description": "API at /apis/policy/v1alpha1", + "operations": [ + { + "type": "v1alpha1.PodDisruptionBudgetList", + "method": "GET", + "summary": "list or watch objects of kind PodDisruptionBudget", + "nickname": "listNamespacedPodDisruptionBudget", + "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.PodDisruptionBudgetList" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + }, + { + "type": "v1alpha1.PodDisruptionBudget", + "method": "POST", + "summary": "create a PodDisruptionBudget", + "nickname": "createNamespacedPodDisruptionBudget", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "v1alpha1.PodDisruptionBudget", + "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.PodDisruptionBudget" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + }, + { + "type": "unversioned.Status", + "method": "DELETE", + "summary": "delete collection of PodDisruptionBudget", + "nickname": "deletecollectionNamespacedPodDisruptionBudget", + "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/policy/v1alpha1/watch/namespaces/{namespace}/poddisruptionbudgets", + "description": "API at /apis/policy/v1alpha1", + "operations": [ + { + "type": "*versioned.Event", + "method": "GET", + "summary": "watch individual changes to a list of PodDisruptionBudget", + "nickname": "watchNamespacedPodDisruptionBudgetList", + "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/json;stream=watch", + "application/vnd.kubernetes.protobuf", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/policy/v1alpha1/namespaces/{namespace}/poddisruptionbudgets/{name}", + "description": "API at /apis/policy/v1alpha1", + "operations": [ + { + "type": "v1alpha1.PodDisruptionBudget", + "method": "GET", + "summary": "read the specified PodDisruptionBudget", + "nickname": "readNamespacedPodDisruptionBudget", + "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 PodDisruptionBudget", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PodDisruptionBudget" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + }, + { + "type": "v1alpha1.PodDisruptionBudget", + "method": "PUT", + "summary": "replace the specified PodDisruptionBudget", + "nickname": "replaceNamespacedPodDisruptionBudget", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "v1alpha1.PodDisruptionBudget", + "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 PodDisruptionBudget", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PodDisruptionBudget" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + }, + { + "type": "v1alpha1.PodDisruptionBudget", + "method": "PATCH", + "summary": "partially update the specified PodDisruptionBudget", + "nickname": "patchNamespacedPodDisruptionBudget", + "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 PodDisruptionBudget", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PodDisruptionBudget" + } + ], + "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 PodDisruptionBudget", + "nickname": "deleteNamespacedPodDisruptionBudget", + "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 PodDisruptionBudget", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "unversioned.Status" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/policy/v1alpha1/watch/namespaces/{namespace}/poddisruptionbudgets/{name}", + "description": "API at /apis/policy/v1alpha1", + "operations": [ + { + "type": "*versioned.Event", + "method": "GET", + "summary": "watch changes to an object of kind PodDisruptionBudget", + "nickname": "watchNamespacedPodDisruptionBudget", + "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 PodDisruptionBudget", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "*versioned.Event" + } + ], + "produces": [ + "application/json", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/policy/v1alpha1/poddisruptionbudgets", + "description": "API at /apis/policy/v1alpha1", + "operations": [ + { + "type": "v1alpha1.PodDisruptionBudgetList", + "method": "GET", + "summary": "list or watch objects of kind PodDisruptionBudget", + "nickname": "listNamespacedPodDisruptionBudget", + "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.PodDisruptionBudgetList" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/policy/v1alpha1/watch/poddisruptionbudgets", + "description": "API at /apis/policy/v1alpha1", + "operations": [ + { + "type": "*versioned.Event", + "method": "GET", + "summary": "watch individual changes to a list of PodDisruptionBudget", + "nickname": "watchNamespacedPodDisruptionBudgetList", + "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/json;stream=watch", + "application/vnd.kubernetes.protobuf", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/policy/v1alpha1/namespaces/{namespace}/poddisruptionbudgets/{name}/status", + "description": "API at /apis/policy/v1alpha1", + "operations": [ + { + "type": "v1alpha1.PodDisruptionBudget", + "method": "PUT", + "summary": "replace status of the specified PodDisruptionBudget", + "nickname": "replaceNamespacedPodDisruptionBudgetStatus", + "parameters": [ + { + "type": "string", + "paramType": "query", + "name": "pretty", + "description": "If 'true', then the output is pretty printed.", + "required": false, + "allowMultiple": false + }, + { + "type": "v1alpha1.PodDisruptionBudget", + "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 PodDisruptionBudget", + "required": true, + "allowMultiple": false + } + ], + "responseMessages": [ + { + "code": 200, + "message": "OK", + "responseModel": "v1alpha1.PodDisruptionBudget" + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "consumes": [ + "*/*" + ] + } + ] + }, + { + "path": "/apis/policy/v1alpha1", + "description": "API at /apis/policy/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.PodDisruptionBudgetList": { + "id": "v1alpha1.PodDisruptionBudgetList", + "description": "PodDisruptionBudgetList is a collection of PodDisruptionBudgets.", + "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.PodDisruptionBudget" + } + } + } + }, + "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.PodDisruptionBudget": { + "id": "v1alpha1.PodDisruptionBudget", + "description": "PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods", + "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.PodDisruptionBudgetSpec", + "description": "Specification of the desired behavior of the PodDisruptionBudget." + }, + "status": { + "$ref": "v1alpha1.PodDisruptionBudgetStatus", + "description": "Most recently observed status of the PodDisruptionBudget." + } + } + }, + "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" + }, + "ownerReferences": { + "type": "array", + "items": { + "$ref": "v1.OwnerReference" + }, + "description": "List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected." + }, + "finalizers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed." + } + } + }, + "v1.OwnerReference": { + "id": "v1.OwnerReference", + "description": "OwnerReference contains enough information to let you identify an owning object. Currently, an owning object must be in the same namespace, so there is no namespace field.", + "required": [ + "apiVersion", + "kind", + "name", + "uid" + ], + "properties": { + "apiVersion": { + "type": "string", + "description": "API version of the referent." + }, + "kind": { + "type": "string", + "description": "Kind of the referent. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + }, + "name": { + "type": "string", + "description": "Name of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names" + }, + "uid": { + "type": "string", + "description": "UID of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#uids" + } + } + }, + "v1alpha1.PodDisruptionBudgetSpec": { + "id": "v1alpha1.PodDisruptionBudgetSpec", + "description": "PodDisruptionBudgetSpec is a description of a PodDisruptionBudget.", + "properties": { + "minAvailable": { + "type": "string", + "description": "The minimum number of pods that must be available simultaneously. This can be either an integer or a string specifying a percentage, e.g. \"28%\"." + }, + "selector": { + "$ref": "unversioned.LabelSelector", + "description": "Label query over pods whose evictions are managed by the disruption budget." + } + } + }, + "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." + } + } + }, + "v1alpha1.PodDisruptionBudgetStatus": { + "id": "v1alpha1.PodDisruptionBudgetStatus", + "description": "PodDisruptionBudgetStatus represents information about the status of a PodDisruptionBudget. Status may trail the actual state of a system.", + "required": [ + "disruptionAllowed", + "currentHealthy", + "desiredHealthy", + "expectedPods" + ], + "properties": { + "disruptionAllowed": { + "type": "boolean", + "description": "Whether or not a disruption is currently allowed." + }, + "currentHealthy": { + "type": "integer", + "format": "int32", + "description": "current number of healthy pods" + }, + "desiredHealthy": { + "type": "integer", + "format": "int32", + "description": "minimum desired number of healthy pods" + }, + "expectedPods": { + "type": "integer", + "format": "int32", + "description": "total number of pods counted by this disruption budget" + } + } + }, + "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." + }, + "orphanDependents": { + "type": "boolean", + "description": "Should the dependent objects be orphaned. If true/false, the \"orphan\" finalizer will be added to/removed from the object's finalizers list." + } + } + }, + "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 0ba82803978..df7a7f1e4a2 100644 --- a/api/swagger-spec/resourceListing.json +++ b/api/swagger-spec/resourceListing.json @@ -45,6 +45,14 @@ "path": "/apis/batch", "description": "get information of a group" }, + { + "path": "/apis/policy/v1alpha1", + "description": "API at /apis/policy/v1alpha1" + }, + { + "path": "/apis/policy", + "description": "get information of a group" + }, { "path": "/apis/apps/v1alpha1", "description": "API at /apis/apps/v1alpha1" diff --git a/hack/test-integration.sh b/hack/test-integration.sh index b4235e6e010..304e7d82e7f 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,apps/v1alpha1,extensions/v1beta1"} +KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1;v1,autoscaling/v1,batch/v1,apps/v1alpha1,policy/v1alpha1,extensions/v1beta1"} # Give integration tests longer to run KUBE_TIMEOUT=${KUBE_TIMEOUT:--timeout 240s} diff --git a/hack/update-generated-swagger-docs.sh b/hack/update-generated-swagger-docs.sh index ad3512b9ea8..4dc13fe6b9c 100755 --- a/hack/update-generated-swagger-docs.sh +++ b/hack/update-generated-swagger-docs.sh @@ -57,7 +57,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 batch/v2alpha1 extensions/v1beta1 apps/v1alpha1 rbac/v1alpha1) +GROUP_VERSIONS=(unversioned v1 authorization/v1beta1 autoscaling/v1 batch/v1 batch/v2alpha1 extensions/v1beta1 apps/v1alpha1 policy/v1alpha1 rbac/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/hack/update-swagger-spec.sh b/hack/update-swagger-spec.sh index f5fb18da339..e288e40237f 100755 --- a/hack/update-swagger-spec.sh +++ b/hack/update-swagger-spec.sh @@ -74,7 +74,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 batch/v2alpha1 extensions/v1beta1 apps/v1alpha1" +DEFAULT_GROUP_VERSIONS="v1 autoscaling/v1 batch/v1 batch/v2alpha1 extensions/v1beta1 apps/v1alpha1 policy/v1alpha1" VERSIONS=${VERSIONS:-$DEFAULT_GROUP_VERSIONS} kube::log::status "Updating " ${SWAGGER_ROOT_DIR} diff --git a/pkg/api/testapi/testapi.go b/pkg/api/testapi/testapi.go index 30899d9b427..e745a4c8718 100644 --- a/pkg/api/testapi/testapi.go +++ b/pkg/api/testapi/testapi.go @@ -33,6 +33,7 @@ import ( "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime/serializer/recognizer" @@ -44,6 +45,7 @@ import ( _ "k8s.io/kubernetes/pkg/apis/componentconfig/install" _ "k8s.io/kubernetes/pkg/apis/extensions/install" _ "k8s.io/kubernetes/pkg/apis/metrics/install" + _ "k8s.io/kubernetes/pkg/apis/policy/install" ) var ( @@ -53,6 +55,7 @@ var ( Batch TestGroup Extensions TestGroup Apps TestGroup + Policy TestGroup Federation TestGroup serializer runtime.SerializerInfo @@ -174,6 +177,13 @@ func init() { internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion), } } + if _, ok := Groups[policy.GroupName]; !ok { + Groups[policy.GroupName] = TestGroup{ + externalGroupVersions: []unversioned.GroupVersion{{Group: policy.GroupName, Version: registered.GroupOrDie(policy.GroupName).GroupVersion.Version}}, + internalGroupVersion: policy.SchemeGroupVersion, + internalTypes: api.Scheme.KnownTypes(policy.SchemeGroupVersion), + } + } if _, ok := Groups[federation.GroupName]; !ok { Groups[federation.GroupName] = TestGroup{ externalGroupVersions: []unversioned.GroupVersion{{Group: federation.GroupName, Version: registered.GroupOrDie(federation.GroupName).GroupVersion.Version}}, @@ -186,6 +196,7 @@ func init() { Autoscaling = Groups[autoscaling.GroupName] Batch = Groups[batch.GroupName] Apps = Groups[apps.GroupName] + Policy = Groups[policy.GroupName] Extensions = Groups[extensions.GroupName] Federation = Groups[federation.GroupName] } diff --git a/pkg/apis/policy/deep_copy_generated.go b/pkg/apis/policy/deep_copy_generated.go index 9b067a0df99..390e4b4a7b4 100644 --- a/pkg/apis/policy/deep_copy_generated.go +++ b/pkg/apis/policy/deep_copy_generated.go @@ -30,6 +30,7 @@ import ( func init() { if err := api.Scheme.AddGeneratedDeepCopyFuncs( DeepCopy_policy_PodDisruptionBudget, + DeepCopy_policy_PodDisruptionBudgetList, DeepCopy_policy_PodDisruptionBudgetSpec, DeepCopy_policy_PodDisruptionBudgetStatus, ); err != nil { @@ -54,6 +55,27 @@ func DeepCopy_policy_PodDisruptionBudget(in PodDisruptionBudget, out *PodDisrupt return nil } +func DeepCopy_policy_PodDisruptionBudgetList(in PodDisruptionBudgetList, out *PodDisruptionBudgetList, 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([]PodDisruptionBudget, len(in)) + for i := range in { + if err := DeepCopy_policy_PodDisruptionBudget(in[i], &(*out)[i], c); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + func DeepCopy_policy_PodDisruptionBudgetSpec(in PodDisruptionBudgetSpec, out *PodDisruptionBudgetSpec, c *conversion.Cloner) error { if err := intstr.DeepCopy_intstr_IntOrString(in.MinAvailable, &out.MinAvailable, c); err != nil { return err diff --git a/pkg/apis/policy/register.go b/pkg/apis/policy/register.go index 842541f5478..7aa010a0f39 100644 --- a/pkg/apis/policy/register.go +++ b/pkg/apis/policy/register.go @@ -47,7 +47,9 @@ func addKnownTypes(scheme *runtime.Scheme) { // TODO this gets cleaned up when the types are fixed scheme.AddKnownTypes(SchemeGroupVersion, &PodDisruptionBudget{}, + &PodDisruptionBudgetList{}, ) } -func (obj *PodDisruptionBudget) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *PodDisruptionBudget) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *PodDisruptionBudgetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } diff --git a/pkg/apis/policy/types.generated.go b/pkg/apis/policy/types.generated.go index 7c7aa18827b..08be370f158 100644 --- a/pkg/apis/policy/types.generated.go +++ b/pkg/apis/policy/types.generated.go @@ -975,3 +975,466 @@ func (x *PodDisruptionBudget) codecDecodeSelfFromArray(l int, d *codec1978.Decod } z.DecSendContainerState(codecSelfer_containerArrayEnd1234) } + +func (x *PodDisruptionBudgetList) 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.encSlicePodDisruptionBudget(([]PodDisruptionBudget)(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.encSlicePodDisruptionBudget(([]PodDisruptionBudget)(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 *PodDisruptionBudgetList) 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 *PodDisruptionBudgetList) 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 = pkg2_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.decSlicePodDisruptionBudget((*[]PodDisruptionBudget)(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 *PodDisruptionBudgetList) 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 = pkg2_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.decSlicePodDisruptionBudget((*[]PodDisruptionBudget)(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) encSlicePodDisruptionBudget(v []PodDisruptionBudget, 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) decSlicePodDisruptionBudget(v *[]PodDisruptionBudget, 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 = []PodDisruptionBudget{} + 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([]PodDisruptionBudget, yyrl1) + } + } else { + yyv1 = make([]PodDisruptionBudget, 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] = PodDisruptionBudget{} + } else { + yyv2 := &yyv1[yyj1] + yyv2.CodecDecodeSelf(d) + } + + } + if yyrt1 { + for ; yyj1 < yyl1; yyj1++ { + yyv1 = append(yyv1, PodDisruptionBudget{}) + yyh1.ElemContainerState(yyj1) + if r.TryDecodeAsNil() { + yyv1[yyj1] = PodDisruptionBudget{} + } else { + yyv3 := &yyv1[yyj1] + yyv3.CodecDecodeSelf(d) + } + + } + } + + } else { + yyj1 := 0 + for ; !r.CheckBreak(); yyj1++ { + + if yyj1 >= len(yyv1) { + yyv1 = append(yyv1, PodDisruptionBudget{}) // var yyz1 PodDisruptionBudget + yyc1 = true + } + yyh1.ElemContainerState(yyj1) + if yyj1 < len(yyv1) { + if r.TryDecodeAsNil() { + yyv1[yyj1] = PodDisruptionBudget{} + } 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 = []PodDisruptionBudget{} + yyc1 = true + } + } + yyh1.End() + if yyc1 { + *v = yyv1 + } +} diff --git a/pkg/apis/policy/types.go b/pkg/apis/policy/types.go index d3851cb9a14..2ecf41bcffd 100644 --- a/pkg/apis/policy/types.go +++ b/pkg/apis/policy/types.go @@ -61,3 +61,10 @@ type PodDisruptionBudget struct { // Most recently observed status of the PodDisruptionBudget. Status PodDisruptionBudgetStatus `json:"status,omitempty"` } + +// PodDisruptionBudgetList is a collection of PodDisruptionBudgets. +type PodDisruptionBudgetList struct { + unversioned.TypeMeta `json:",inline"` + unversioned.ListMeta `json:"metadata,omitempty"` + Items []PodDisruptionBudget `json:"items"` +} diff --git a/pkg/apis/policy/v1alpha1/conversion_generated.go b/pkg/apis/policy/v1alpha1/conversion_generated.go index 17e4f4c9c62..bc9ee703fd9 100644 --- a/pkg/apis/policy/v1alpha1/conversion_generated.go +++ b/pkg/apis/policy/v1alpha1/conversion_generated.go @@ -31,6 +31,8 @@ func init() { if err := api.Scheme.AddGeneratedConversionFuncs( Convert_v1alpha1_PodDisruptionBudget_To_policy_PodDisruptionBudget, Convert_policy_PodDisruptionBudget_To_v1alpha1_PodDisruptionBudget, + Convert_v1alpha1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList, + Convert_policy_PodDisruptionBudgetList_To_v1alpha1_PodDisruptionBudgetList, Convert_v1alpha1_PodDisruptionBudgetSpec_To_policy_PodDisruptionBudgetSpec, Convert_policy_PodDisruptionBudgetSpec_To_v1alpha1_PodDisruptionBudgetSpec, Convert_v1alpha1_PodDisruptionBudgetStatus_To_policy_PodDisruptionBudgetStatus, @@ -83,6 +85,56 @@ func Convert_policy_PodDisruptionBudget_To_v1alpha1_PodDisruptionBudget(in *poli return autoConvert_policy_PodDisruptionBudget_To_v1alpha1_PodDisruptionBudget(in, out, s) } +func autoConvert_v1alpha1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList(in *PodDisruptionBudgetList, out *policy.PodDisruptionBudgetList, s conversion.Scope) error { + 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([]policy.PodDisruptionBudget, len(*in)) + for i := range *in { + if err := Convert_v1alpha1_PodDisruptionBudget_To_policy_PodDisruptionBudget(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +func Convert_v1alpha1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList(in *PodDisruptionBudgetList, out *policy.PodDisruptionBudgetList, s conversion.Scope) error { + return autoConvert_v1alpha1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList(in, out, s) +} + +func autoConvert_policy_PodDisruptionBudgetList_To_v1alpha1_PodDisruptionBudgetList(in *policy.PodDisruptionBudgetList, out *PodDisruptionBudgetList, s conversion.Scope) error { + 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([]PodDisruptionBudget, len(*in)) + for i := range *in { + if err := Convert_policy_PodDisruptionBudget_To_v1alpha1_PodDisruptionBudget(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + +func Convert_policy_PodDisruptionBudgetList_To_v1alpha1_PodDisruptionBudgetList(in *policy.PodDisruptionBudgetList, out *PodDisruptionBudgetList, s conversion.Scope) error { + return autoConvert_policy_PodDisruptionBudgetList_To_v1alpha1_PodDisruptionBudgetList(in, out, s) +} + func autoConvert_v1alpha1_PodDisruptionBudgetSpec_To_policy_PodDisruptionBudgetSpec(in *PodDisruptionBudgetSpec, out *policy.PodDisruptionBudgetSpec, s conversion.Scope) error { if err := api.Convert_intstr_IntOrString_To_intstr_IntOrString(&in.MinAvailable, &out.MinAvailable, s); err != nil { return err diff --git a/pkg/apis/policy/v1alpha1/deep_copy_generated.go b/pkg/apis/policy/v1alpha1/deep_copy_generated.go index 307fa7d4d96..74680aff846 100644 --- a/pkg/apis/policy/v1alpha1/deep_copy_generated.go +++ b/pkg/apis/policy/v1alpha1/deep_copy_generated.go @@ -31,6 +31,7 @@ import ( func init() { if err := api.Scheme.AddGeneratedDeepCopyFuncs( DeepCopy_v1alpha1_PodDisruptionBudget, + DeepCopy_v1alpha1_PodDisruptionBudgetList, DeepCopy_v1alpha1_PodDisruptionBudgetSpec, DeepCopy_v1alpha1_PodDisruptionBudgetStatus, ); err != nil { @@ -55,6 +56,27 @@ func DeepCopy_v1alpha1_PodDisruptionBudget(in PodDisruptionBudget, out *PodDisru return nil } +func DeepCopy_v1alpha1_PodDisruptionBudgetList(in PodDisruptionBudgetList, out *PodDisruptionBudgetList, 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([]PodDisruptionBudget, len(in)) + for i := range in { + if err := DeepCopy_v1alpha1_PodDisruptionBudget(in[i], &(*out)[i], c); err != nil { + return err + } + } + } else { + out.Items = nil + } + return nil +} + func DeepCopy_v1alpha1_PodDisruptionBudgetSpec(in PodDisruptionBudgetSpec, out *PodDisruptionBudgetSpec, c *conversion.Cloner) error { if err := intstr.DeepCopy_intstr_IntOrString(in.MinAvailable, &out.MinAvailable, c); err != nil { return err diff --git a/pkg/apis/policy/v1alpha1/generated.pb.go b/pkg/apis/policy/v1alpha1/generated.pb.go index 9ebd5b3625c..867a6b0a6dd 100644 --- a/pkg/apis/policy/v1alpha1/generated.pb.go +++ b/pkg/apis/policy/v1alpha1/generated.pb.go @@ -26,6 +26,7 @@ limitations under the License. It has these top-level messages: PodDisruptionBudget + PodDisruptionBudgetList PodDisruptionBudgetSpec PodDisruptionBudgetStatus */ @@ -48,6 +49,10 @@ func (m *PodDisruptionBudget) Reset() { *m = PodDisruptionBudget{} } func (m *PodDisruptionBudget) String() string { return proto.CompactTextString(m) } func (*PodDisruptionBudget) ProtoMessage() {} +func (m *PodDisruptionBudgetList) Reset() { *m = PodDisruptionBudgetList{} } +func (m *PodDisruptionBudgetList) String() string { return proto.CompactTextString(m) } +func (*PodDisruptionBudgetList) ProtoMessage() {} + func (m *PodDisruptionBudgetSpec) Reset() { *m = PodDisruptionBudgetSpec{} } func (m *PodDisruptionBudgetSpec) String() string { return proto.CompactTextString(m) } func (*PodDisruptionBudgetSpec) ProtoMessage() {} @@ -58,6 +63,7 @@ func (*PodDisruptionBudgetStatus) ProtoMessage() {} func init() { proto.RegisterType((*PodDisruptionBudget)(nil), "k8s.io.kubernetes.pkg.apis.policy.v1alpha1.PodDisruptionBudget") + proto.RegisterType((*PodDisruptionBudgetList)(nil), "k8s.io.kubernetes.pkg.apis.policy.v1alpha1.PodDisruptionBudgetList") proto.RegisterType((*PodDisruptionBudgetSpec)(nil), "k8s.io.kubernetes.pkg.apis.policy.v1alpha1.PodDisruptionBudgetSpec") proto.RegisterType((*PodDisruptionBudgetStatus)(nil), "k8s.io.kubernetes.pkg.apis.policy.v1alpha1.PodDisruptionBudgetStatus") } @@ -103,6 +109,44 @@ func (m *PodDisruptionBudget) MarshalTo(data []byte) (int, error) { return i, nil } +func (m *PodDisruptionBudgetList) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *PodDisruptionBudgetList) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + data[i] = 0xa + i++ + i = encodeVarintGenerated(data, i, uint64(m.ListMeta.Size())) + n4, err := m.ListMeta.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n4 + if len(m.Items) > 0 { + for _, msg := range m.Items { + data[i] = 0x12 + i++ + i = encodeVarintGenerated(data, i, uint64(msg.Size())) + n, err := msg.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n + } + } + return i, nil +} + func (m *PodDisruptionBudgetSpec) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) @@ -121,20 +165,20 @@ func (m *PodDisruptionBudgetSpec) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintGenerated(data, i, uint64(m.MinAvailable.Size())) - n4, err := m.MinAvailable.MarshalTo(data[i:]) + n5, err := m.MinAvailable.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n4 + i += n5 if m.Selector != nil { data[i] = 0x12 i++ i = encodeVarintGenerated(data, i, uint64(m.Selector.Size())) - n5, err := m.Selector.MarshalTo(data[i:]) + n6, err := m.Selector.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n5 + i += n6 } return i, nil } @@ -213,6 +257,20 @@ func (m *PodDisruptionBudget) Size() (n int) { return n } +func (m *PodDisruptionBudgetList) Size() (n int) { + var l int + _ = l + l = m.ListMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Items) > 0 { + for _, e := range m.Items { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + func (m *PodDisruptionBudgetSpec) Size() (n int) { var l int _ = l @@ -388,6 +446,117 @@ func (m *PodDisruptionBudget) Unmarshal(data []byte) error { } return nil } +func (m *PodDisruptionBudgetList) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PodDisruptionBudgetList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PodDisruptionBudgetList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ListMeta.Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Items = append(m.Items, PodDisruptionBudget{}) + if err := m.Items[len(m.Items)-1].Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *PodDisruptionBudgetSpec) Unmarshal(data []byte) error { l := len(data) iNdEx := 0 diff --git a/pkg/apis/policy/v1alpha1/generated.proto b/pkg/apis/policy/v1alpha1/generated.proto index 24e3298531c..866d0ae5788 100644 --- a/pkg/apis/policy/v1alpha1/generated.proto +++ b/pkg/apis/policy/v1alpha1/generated.proto @@ -41,6 +41,13 @@ message PodDisruptionBudget { optional PodDisruptionBudgetStatus status = 3; } +// PodDisruptionBudgetList is a collection of PodDisruptionBudgets. +message PodDisruptionBudgetList { + optional k8s.io.kubernetes.pkg.api.unversioned.ListMeta metadata = 1; + + repeated PodDisruptionBudget items = 2; +} + // PodDisruptionBudgetSpec is a description of a PodDisruptionBudget. message PodDisruptionBudgetSpec { // The minimum number of pods that must be available simultaneously. This diff --git a/pkg/apis/policy/v1alpha1/register.go b/pkg/apis/policy/v1alpha1/register.go index 2181e6c2c0f..ac41af6dbf8 100644 --- a/pkg/apis/policy/v1alpha1/register.go +++ b/pkg/apis/policy/v1alpha1/register.go @@ -40,9 +40,11 @@ func AddToScheme(scheme *runtime.Scheme) { func addKnownTypes(scheme *runtime.Scheme) { scheme.AddKnownTypes(SchemeGroupVersion, &PodDisruptionBudget{}, + &PodDisruptionBudgetList{}, ) // Add the watch version that applies versionedwatch.AddToGroupVersion(scheme, SchemeGroupVersion) } -func (obj *PodDisruptionBudget) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *PodDisruptionBudget) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *PodDisruptionBudgetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } diff --git a/pkg/apis/policy/v1alpha1/types.generated.go b/pkg/apis/policy/v1alpha1/types.generated.go index 52d6415415f..7ed4308bcc6 100644 --- a/pkg/apis/policy/v1alpha1/types.generated.go +++ b/pkg/apis/policy/v1alpha1/types.generated.go @@ -975,3 +975,466 @@ func (x *PodDisruptionBudget) codecDecodeSelfFromArray(l int, d *codec1978.Decod } z.DecSendContainerState(codecSelfer_containerArrayEnd1234) } + +func (x *PodDisruptionBudgetList) 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.encSlicePodDisruptionBudget(([]PodDisruptionBudget)(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.encSlicePodDisruptionBudget(([]PodDisruptionBudget)(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 *PodDisruptionBudgetList) 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 *PodDisruptionBudgetList) 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 = pkg2_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.decSlicePodDisruptionBudget((*[]PodDisruptionBudget)(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 *PodDisruptionBudgetList) 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 = pkg2_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.decSlicePodDisruptionBudget((*[]PodDisruptionBudget)(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) encSlicePodDisruptionBudget(v []PodDisruptionBudget, 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) decSlicePodDisruptionBudget(v *[]PodDisruptionBudget, 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 = []PodDisruptionBudget{} + 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([]PodDisruptionBudget, yyrl1) + } + } else { + yyv1 = make([]PodDisruptionBudget, 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] = PodDisruptionBudget{} + } else { + yyv2 := &yyv1[yyj1] + yyv2.CodecDecodeSelf(d) + } + + } + if yyrt1 { + for ; yyj1 < yyl1; yyj1++ { + yyv1 = append(yyv1, PodDisruptionBudget{}) + yyh1.ElemContainerState(yyj1) + if r.TryDecodeAsNil() { + yyv1[yyj1] = PodDisruptionBudget{} + } else { + yyv3 := &yyv1[yyj1] + yyv3.CodecDecodeSelf(d) + } + + } + } + + } else { + yyj1 := 0 + for ; !r.CheckBreak(); yyj1++ { + + if yyj1 >= len(yyv1) { + yyv1 = append(yyv1, PodDisruptionBudget{}) // var yyz1 PodDisruptionBudget + yyc1 = true + } + yyh1.ElemContainerState(yyj1) + if yyj1 < len(yyv1) { + if r.TryDecodeAsNil() { + yyv1[yyj1] = PodDisruptionBudget{} + } 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 = []PodDisruptionBudget{} + yyc1 = true + } + } + yyh1.End() + if yyc1 { + *v = yyv1 + } +} diff --git a/pkg/apis/policy/v1alpha1/types.go b/pkg/apis/policy/v1alpha1/types.go index baf5d9e1648..1f3265ae272 100644 --- a/pkg/apis/policy/v1alpha1/types.go +++ b/pkg/apis/policy/v1alpha1/types.go @@ -62,3 +62,10 @@ type PodDisruptionBudget struct { // Most recently observed status of the PodDisruptionBudget. Status PodDisruptionBudgetStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` } + +// PodDisruptionBudgetList is a collection of PodDisruptionBudgets. +type PodDisruptionBudgetList struct { + unversioned.TypeMeta `json:",inline"` + unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + Items []PodDisruptionBudget `json:"items" protobuf:"bytes,2,rep,name=items"` +} diff --git a/pkg/apis/policy/v1alpha1/types_swagger_doc_generated.go b/pkg/apis/policy/v1alpha1/types_swagger_doc_generated.go new file mode 100644 index 00000000000..8ca1782f4f9 --- /dev/null +++ b/pkg/apis/policy/v1alpha1/types_swagger_doc_generated.go @@ -0,0 +1,70 @@ +/* +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 + +// 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_PodDisruptionBudget = map[string]string{ + "": "PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods", + "spec": "Specification of the desired behavior of the PodDisruptionBudget.", + "status": "Most recently observed status of the PodDisruptionBudget.", +} + +func (PodDisruptionBudget) SwaggerDoc() map[string]string { + return map_PodDisruptionBudget +} + +var map_PodDisruptionBudgetList = map[string]string{ + "": "PodDisruptionBudgetList is a collection of PodDisruptionBudgets.", +} + +func (PodDisruptionBudgetList) SwaggerDoc() map[string]string { + return map_PodDisruptionBudgetList +} + +var map_PodDisruptionBudgetSpec = map[string]string{ + "": "PodDisruptionBudgetSpec is a description of a PodDisruptionBudget.", + "minAvailable": "The minimum number of pods that must be available simultaneously. This can be either an integer or a string specifying a percentage, e.g. \"28%\".", + "selector": "Label query over pods whose evictions are managed by the disruption budget.", +} + +func (PodDisruptionBudgetSpec) SwaggerDoc() map[string]string { + return map_PodDisruptionBudgetSpec +} + +var map_PodDisruptionBudgetStatus = map[string]string{ + "": "PodDisruptionBudgetStatus represents information about the status of a PodDisruptionBudget. Status may trail the actual state of a system.", + "disruptionAllowed": "Whether or not a disruption is currently allowed.", + "currentHealthy": "current number of healthy pods", + "desiredHealthy": "minimum desired number of healthy pods", + "expectedPods": "total number of pods counted by this disruption budget", +} + +func (PodDisruptionBudgetStatus) SwaggerDoc() map[string]string { + return map_PodDisruptionBudgetStatus +} + +// AUTO-GENERATED FUNCTIONS END HERE diff --git a/pkg/apis/policy/validation/validation.go b/pkg/apis/policy/validation/validation.go index d9ce117ae46..6d40450ba88 100644 --- a/pkg/apis/policy/validation/validation.go +++ b/pkg/apis/policy/validation/validation.go @@ -17,12 +17,33 @@ limitations under the License. package validation import ( + "reflect" + unversionedvalidation "k8s.io/kubernetes/pkg/api/unversioned/validation" extensionsvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/util/validation/field" ) +func ValidatePodDisruptionBudget(pdb *policy.PodDisruptionBudget) field.ErrorList { + allErrs := ValidatePodDisruptionBudgetSpec(pdb.Spec, field.NewPath("spec")) + return allErrs +} + +func ValidatePodDisruptionBudgetUpdate(pdb, oldPdb *policy.PodDisruptionBudget) field.ErrorList { + allErrs := field.ErrorList{} + + restoreGeneration := pdb.Generation + pdb.Generation = oldPdb.Generation + + if !reflect.DeepEqual(pdb, oldPdb) { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to poddisruptionbudget spec are forbidden.")) + } + + pdb.Generation = restoreGeneration + return allErrs +} + func ValidatePodDisruptionBudgetSpec(spec policy.PodDisruptionBudgetSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} diff --git a/pkg/client/clientset_generated/internalclientset/import_known_versions.go b/pkg/client/clientset_generated/internalclientset/import_known_versions.go index 291037d5232..7e7709bcfd0 100644 --- a/pkg/client/clientset_generated/internalclientset/import_known_versions.go +++ b/pkg/client/clientset_generated/internalclientset/import_known_versions.go @@ -29,6 +29,7 @@ import ( _ "k8s.io/kubernetes/pkg/apis/componentconfig/install" _ "k8s.io/kubernetes/pkg/apis/extensions/install" _ "k8s.io/kubernetes/pkg/apis/metrics/install" + _ "k8s.io/kubernetes/pkg/apis/policy/install" ) func init() { diff --git a/pkg/client/unversioned/client.go b/pkg/client/unversioned/client.go index f81b41d56a7..67aafe6bd40 100644 --- a/pkg/client/unversioned/client.go +++ b/pkg/client/unversioned/client.go @@ -120,6 +120,7 @@ type Client struct { *BatchClient *ExtensionsClient *AppsClient + *PolicyClient *discovery.DiscoveryClient } diff --git a/pkg/client/unversioned/helper.go b/pkg/client/unversioned/helper.go index 0f2d6694597..058041e2cbf 100644 --- a/pkg/client/unversioned/helper.go +++ b/pkg/client/unversioned/helper.go @@ -26,6 +26,7 @@ import ( "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/typed/discovery" "k8s.io/kubernetes/pkg/util/sets" @@ -85,6 +86,15 @@ func New(c *restclient.Config) (*Client, error) { return nil, err } } + var policyClient *PolicyClient + if registered.IsRegistered(policy.GroupName) { + policyConfig := *c + policyClient, err = NewPolicy(&policyConfig) + if err != nil { + return nil, err + } + } + var appsClient *AppsClient if registered.IsRegistered(apps.GroupName) { appsConfig := *c @@ -94,7 +104,7 @@ func New(c *restclient.Config) (*Client, error) { } } - return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, BatchClient: batchClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient, AppsClient: appsClient}, nil + return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, BatchClient: batchClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient, AppsClient: appsClient, PolicyClient: policyClient}, nil } // MatchesServerVersion queries the server to compares the build version diff --git a/pkg/client/unversioned/pod_disruption_budgets.go b/pkg/client/unversioned/pod_disruption_budgets.go new file mode 100644 index 00000000000..14f373f3760 --- /dev/null +++ b/pkg/client/unversioned/pod_disruption_budgets.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/policy" + "k8s.io/kubernetes/pkg/watch" +) + +// PodDisruptionBudgetNamespacer has methods to work with PodDisruptionBudget resources in a namespace +type PodDisruptionBudgetNamespacer interface { + PodDisruptionBudgets(namespace string) PodDisruptionBudgetInterface +} + +// PodDisruptionBudgetInterface exposes methods to work on PodDisruptionBudget resources. +type PodDisruptionBudgetInterface interface { + List(opts api.ListOptions) (*policy.PodDisruptionBudgetList, error) + Get(name string) (*policy.PodDisruptionBudget, error) + Create(podDisruptionBudget *policy.PodDisruptionBudget) (*policy.PodDisruptionBudget, error) + Update(podDisruptionBudget *policy.PodDisruptionBudget) (*policy.PodDisruptionBudget, error) + Delete(name string, options *api.DeleteOptions) error + Watch(opts api.ListOptions) (watch.Interface, error) + UpdateStatus(podDisruptionBudget *policy.PodDisruptionBudget) (*policy.PodDisruptionBudget, error) +} + +// podDisruptionBudget implements PodDisruptionBudgetNamespacer interface +type podDisruptionBudget struct { + r *PolicyClient + ns string +} + +// newPodDisruptionBudget returns a podDisruptionBudget +func newPodDisruptionBudget(c *PolicyClient, namespace string) *podDisruptionBudget { + return &podDisruptionBudget{c, namespace} +} + +// List returns a list of podDisruptionBudget that match the label and field selectors. +func (c *podDisruptionBudget) List(opts api.ListOptions) (result *policy.PodDisruptionBudgetList, err error) { + result = &policy.PodDisruptionBudgetList{} + err = c.r.Get().Namespace(c.ns).Resource("poddisruptionbudgets").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular podDisruptionBudget. +func (c *podDisruptionBudget) Get(name string) (result *policy.PodDisruptionBudget, err error) { + result = &policy.PodDisruptionBudget{} + err = c.r.Get().Namespace(c.ns).Resource("poddisruptionbudgets").Name(name).Do().Into(result) + return +} + +// Create creates a new podDisruptionBudget. +func (c *podDisruptionBudget) Create(podDisruptionBudget *policy.PodDisruptionBudget) (result *policy.PodDisruptionBudget, err error) { + result = &policy.PodDisruptionBudget{} + err = c.r.Post().Namespace(c.ns).Resource("poddisruptionbudgets").Body(podDisruptionBudget).Do().Into(result) + return +} + +// Update updates an existing podDisruptionBudget. +func (c *podDisruptionBudget) Update(podDisruptionBudget *policy.PodDisruptionBudget) (result *policy.PodDisruptionBudget, err error) { + result = &policy.PodDisruptionBudget{} + err = c.r.Put().Namespace(c.ns).Resource("poddisruptionbudgets").Name(podDisruptionBudget.Name).Body(podDisruptionBudget).Do().Into(result) + return +} + +// Delete deletes a podDisruptionBudget, returns error if one occurs. +func (c *podDisruptionBudget) Delete(name string, options *api.DeleteOptions) (err error) { + return c.r.Delete().Namespace(c.ns).Resource("poddisruptionbudgets").Name(name).Body(options).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested podDisruptionBudget. +func (c *podDisruptionBudget) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("poddisruptionbudgets"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// UpdateStatus takes the name of the podDisruptionBudget and the new status. Returns the server's representation of the podDisruptionBudget, and an error, if it occurs. +func (c *podDisruptionBudget) UpdateStatus(podDisruptionBudget *policy.PodDisruptionBudget) (result *policy.PodDisruptionBudget, err error) { + result = &policy.PodDisruptionBudget{} + err = c.r.Put().Namespace(c.ns).Resource("poddisruptionbudgets").Name(podDisruptionBudget.Name).SubResource("status").Body(podDisruptionBudget).Do().Into(result) + return +} diff --git a/pkg/client/unversioned/policy.go b/pkg/client/unversioned/policy.go new file mode 100644 index 00000000000..8b06ce275ac --- /dev/null +++ b/pkg/client/unversioned/policy.go @@ -0,0 +1,83 @@ +/* +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/policy" + "k8s.io/kubernetes/pkg/client/restclient" +) + +type PolicyInterface interface { + PodDisruptionBudgetNamespacer +} + +// PolicyClient is used to interact with Kubernetes batch features. +type PolicyClient struct { + *restclient.RESTClient +} + +func (c *PolicyClient) PodDisruptionBudgets(namespace string) PodDisruptionBudgetInterface { + return newPodDisruptionBudget(c, namespace) +} + +func NewPolicy(c *restclient.Config) (*PolicyClient, error) { + config := *c + if err := setPolicyDefaults(&config); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &PolicyClient{client}, nil +} + +func NewPolicyOrDie(c *restclient.Config) *PolicyClient { + client, err := NewPolicy(c) + if err != nil { + panic(err) + } + return client +} + +func setPolicyDefaults(config *restclient.Config) error { + g, err := registered.Group(policy.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) + config.NegotiatedSerializer = api.Codecs + if config.QPS == 0 { + config.QPS = 5 + } + if config.Burst == 0 { + config.Burst = 10 + } + return nil +} diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index a19e5d42f40..3b877fc6bde 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -47,6 +47,7 @@ import ( "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/metrics" + "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/client/restclient" client "k8s.io/kubernetes/pkg/client/unversioned" clientset "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset" @@ -321,6 +322,8 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { return c.AutoscalingClient.RESTClient, nil case batch.GroupName: return c.BatchClient.RESTClient, nil + case policy.GroupName: + return c.PolicyClient.RESTClient, nil case apps.GroupName: return c.AppsClient.RESTClient, nil case extensions.GroupName: @@ -900,6 +903,12 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { } return getSchemaAndValidate(c.c.AutoscalingClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } + if gvk.Group == policy.GroupName { + if c.c.PolicyClient == nil { + return errors.New("unable to validate: no policy client") + } + return getSchemaAndValidate(c.c.PolicyClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) + } if gvk.Group == apps.GroupName { if c.c.AppsClient == nil { return errors.New("unable to validate: no autoscaling client") diff --git a/pkg/master/master.go b/pkg/master/master.go index 93b396c91f8..0e576b5c4cb 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -41,6 +41,8 @@ import ( batchapiv2alpha1 "k8s.io/kubernetes/pkg/apis/batch/v2alpha1" "k8s.io/kubernetes/pkg/apis/extensions" extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" + "k8s.io/kubernetes/pkg/apis/policy" + policyapiv1alpha1 "k8s.io/kubernetes/pkg/apis/policy/v1alpha1" "k8s.io/kubernetes/pkg/apiserver" apiservermetrics "k8s.io/kubernetes/pkg/apiserver/metrics" "k8s.io/kubernetes/pkg/genericapiserver" @@ -67,6 +69,7 @@ import ( pvcetcd "k8s.io/kubernetes/pkg/registry/persistentvolumeclaim/etcd" petsetetcd "k8s.io/kubernetes/pkg/registry/petset/etcd" podetcd "k8s.io/kubernetes/pkg/registry/pod/etcd" + poddisruptionbudgetetcd "k8s.io/kubernetes/pkg/registry/poddisruptionbudget/etcd" pspetcd "k8s.io/kubernetes/pkg/registry/podsecuritypolicy/etcd" podtemplateetcd "k8s.io/kubernetes/pkg/registry/podtemplate/etcd" replicasetetcd "k8s.io/kubernetes/pkg/registry/replicaset/etcd" @@ -344,6 +347,38 @@ func (m *Master) InstallAPIs(c *Config) { allGroups = append(allGroups, group) } + if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(policyapiv1alpha1.SchemeGroupVersion) { + policyResources := m.getPolicyResources(c) + policyGroupMeta := registered.GroupOrDie(policy.GroupName) + + // Hard code preferred group version to policy/v1alpha1 + policyGroupMeta.GroupVersion = policyapiv1alpha1.SchemeGroupVersion + + apiGroupInfo := genericapiserver.APIGroupInfo{ + GroupMeta: *policyGroupMeta, + VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ + "v1alpha1": policyResources, + }, + OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, + Scheme: api.Scheme, + ParameterCodec: api.ParameterCodec, + NegotiatedSerializer: api.Codecs, + } + apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) + + policyGVForDiscovery := unversioned.GroupVersionForDiscovery{ + GroupVersion: policyGroupMeta.GroupVersion.String(), + Version: policyGroupMeta.GroupVersion.Version, + } + group := unversioned.APIGroup{ + Name: policyGroupMeta.GroupVersion.Group, + Versions: []unversioned.GroupVersionForDiscovery{policyGVForDiscovery}, + PreferredVersion: policyGVForDiscovery, + } + allGroups = append(allGroups, group) + + } + if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(appsapi.SchemeGroupVersion) { appsResources := m.getAppsResources(c) appsGroupMeta := registered.GroupOrDie(apps.GroupName) @@ -839,6 +874,20 @@ func (m *Master) getBatchResources(c *Config, version unversioned.GroupVersion) return storage } +// getPolicyResources returns the resources for policy api +func (m *Master) getPolicyResources(c *Config) map[string]rest.Storage { + // TODO update when we support more than one version of this group + version := policyapiv1alpha1.SchemeGroupVersion + + storage := map[string]rest.Storage{} + if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("poddisruptionbudgets")) { + poddisruptionbudgetStorage, poddisruptionbudgetStatusStorage := poddisruptionbudgetetcd.NewREST(m.GetRESTOptionsOrDie(c, policy.Resource("poddisruptionbudgets"))) + storage["poddisruptionbudgets"] = poddisruptionbudgetStorage + storage["poddisruptionbudgets/status"] = poddisruptionbudgetStatusStorage + } + return storage +} + // getPetSetResources returns the resources for apps api func (m *Master) getAppsResources(c *Config) map[string]rest.Storage { // TODO update when we support more than one version of this group @@ -905,7 +954,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, appsapi.SchemeGroupVersion) + ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion, appsapi.SchemeGroupVersion, policyapiv1alpha1.SchemeGroupVersion) // all extensions resources except these are disabled by default ret.EnableResources( diff --git a/pkg/registry/cachesize/cachesize.go b/pkg/registry/cachesize/cachesize.go index 048597babca..99161e1093e 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" + PodDisruptionBudget Resource = "poddisruptionbudgets" PetSet Resource = "petset" Jobs Resource = "jobs" LimitRanges Resource = "limitranges" @@ -61,6 +62,7 @@ func init() { watchCacheSizes[HorizontalPodAutoscalers] = 100 watchCacheSizes[Ingress] = 100 watchCacheSizes[PetSet] = 100 + watchCacheSizes[PodDisruptionBudget] = 100 watchCacheSizes[Jobs] = 100 watchCacheSizes[LimitRanges] = 100 watchCacheSizes[Namespaces] = 100 diff --git a/pkg/registry/poddisruptionbudget/doc.go b/pkg/registry/poddisruptionbudget/doc.go new file mode 100644 index 00000000000..717f26d21d8 --- /dev/null +++ b/pkg/registry/poddisruptionbudget/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 poddisruptionbudget diff --git a/pkg/registry/poddisruptionbudget/etcd/etcd.go b/pkg/registry/poddisruptionbudget/etcd/etcd.go new file mode 100644 index 00000000000..d148cb18870 --- /dev/null +++ b/pkg/registry/poddisruptionbudget/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" + policyapi "k8s.io/kubernetes/pkg/apis/policy" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/registry/cachesize" + "k8s.io/kubernetes/pkg/registry/generic" + "k8s.io/kubernetes/pkg/registry/generic/registry" + "k8s.io/kubernetes/pkg/registry/poddisruptionbudget" + "k8s.io/kubernetes/pkg/runtime" +) + +// rest implements a RESTStorage for pod disruption budgets against etcd +type REST struct { + *registry.Store +} + +// NewREST returns a RESTStorage object that will work against pod disruption budgets. +func NewREST(opts generic.RESTOptions) (*REST, *StatusREST) { + prefix := "/poddisruptionbudgets" + + newListFunc := func() runtime.Object { return &policyapi.PodDisruptionBudgetList{} } + storageInterface := opts.Decorator( + opts.Storage, cachesize.GetWatchCacheSizeByResource(cachesize.PodDisruptionBudget), &policyapi.PodDisruptionBudget{}, prefix, poddisruptionbudget.Strategy, newListFunc) + + store := ®istry.Store{ + NewFunc: func() runtime.Object { return &policyapi.PodDisruptionBudget{} }, + + // NewListFunc returns an object capable of storing results of an etcd list. + NewListFunc: newListFunc, + // Produces a podDisruptionBudget 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 registry.NamespaceKeyRootFunc(ctx, prefix) + }, + // Produces a podDisruptionBudget 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 registry.NamespaceKeyFunc(ctx, prefix, name) + }, + // Retrieve the name field of a pod disruption budget + ObjectNameFunc: func(obj runtime.Object) (string, error) { + return obj.(*policyapi.PodDisruptionBudget).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 poddisruptionbudget.MatchPodDisruptionBudget(label, field) + }, + QualifiedResource: policyapi.Resource("poddisruptionbudgets"), + DeleteCollectionWorkers: opts.DeleteCollectionWorkers, + + // Used to validate controller creation + CreateStrategy: poddisruptionbudget.Strategy, + + // Used to validate controller updates + UpdateStrategy: poddisruptionbudget.Strategy, + DeleteStrategy: poddisruptionbudget.Strategy, + + Storage: storageInterface, + } + statusStore := *store + statusStore.UpdateStrategy = poddisruptionbudget.StatusStrategy + return &REST{store}, &StatusREST{store: &statusStore} +} + +// StatusREST implements the REST endpoint for changing the status of an podDisruptionBudget +type StatusREST struct { + store *registry.Store +} + +func (r *StatusREST) New() runtime.Object { + return &policyapi.PodDisruptionBudget{} +} + +// 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/poddisruptionbudget/etcd/etcd_test.go b/pkg/registry/poddisruptionbudget/etcd/etcd_test.go new file mode 100644 index 00000000000..02badac2395 --- /dev/null +++ b/pkg/registry/poddisruptionbudget/etcd/etcd_test.go @@ -0,0 +1,167 @@ +/* +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/policy" + "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" + "k8s.io/kubernetes/pkg/util/intstr" +) + +func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) { + etcdStorage, server := registrytest.NewEtcdStorage(t, policy.GroupName) + restOptions := generic.RESTOptions{Storage: etcdStorage, Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1} + podDisruptionBudgetStorage, statusStorage := NewREST(restOptions) + return podDisruptionBudgetStorage, statusStorage, server +} + +// createPodDisruptionBudget is a helper function that returns a PodDisruptionBudget with the updated resource version. +func createPodDisruptionBudget(storage *REST, pdb policy.PodDisruptionBudget, t *testing.T) (policy.PodDisruptionBudget, error) { + ctx := api.WithNamespace(api.NewContext(), pdb.Namespace) + obj, err := storage.Create(ctx, &pdb) + if err != nil { + t.Errorf("Failed to create PodDisruptionBudget, %v", err) + } + newPS := obj.(*policy.PodDisruptionBudget) + return *newPS, nil +} + +func validNewPodDisruptionBudget() *policy.PodDisruptionBudget { + return &policy.PodDisruptionBudget{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: api.NamespaceDefault, + Labels: map[string]string{"a": "b"}, + }, + Spec: policy.PodDisruptionBudgetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"a": "b"}}, + MinAvailable: intstr.FromInt(7), + }, + Status: policy.PodDisruptionBudgetStatus{}, + } +} + +func TestCreate(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + pdb := validNewPodDisruptionBudget() + pdb.ObjectMeta = api.ObjectMeta{} + test.TestCreate( + // valid + pdb, + // 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("/poddisruptionbudgets/" + api.NamespaceDefault + "/foo") + validPodDisruptionBudget := validNewPodDisruptionBudget() + if err := storage.Storage.Create(ctx, key, validPodDisruptionBudget, nil, 0); err != nil { + t.Fatalf("unexpected error: %v", err) + } + update := policy.PodDisruptionBudget{ + ObjectMeta: validPodDisruptionBudget.ObjectMeta, + Spec: policy.PodDisruptionBudgetSpec{ + MinAvailable: intstr.FromInt(8), + }, + Status: policy.PodDisruptionBudgetStatus{ + ExpectedPods: 8, + }, + } + + 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) + } + + pdb := obj.(*policy.PodDisruptionBudget) + if pdb.Spec.MinAvailable.IntValue() != 7 { + t.Errorf("we expected .spec.replicas to not be updated but it was updated to %v", pdb.Spec.MinAvailable) + } + if pdb.Status.ExpectedPods != 8 { + t.Errorf("we expected .status.replicas to be updated to %d but it was %v", 7, pdb.Status.ExpectedPods) + } +} + +func TestGet(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + test.TestGet(validNewPodDisruptionBudget()) +} + +func TestList(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + test.TestList(validNewPodDisruptionBudget()) +} + +func TestDelete(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + test.TestDelete(validNewPodDisruptionBudget()) +} + +func TestWatch(t *testing.T) { + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + test.TestWatch( + validNewPodDisruptionBudget(), + // 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/poddisruptionbudget/strategy.go b/pkg/registry/poddisruptionbudget/strategy.go new file mode 100644 index 00000000000..4b32b953263 --- /dev/null +++ b/pkg/registry/poddisruptionbudget/strategy.go @@ -0,0 +1,138 @@ +/* +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 poddisruptionbudget + +import ( + "fmt" + "reflect" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/policy" + "k8s.io/kubernetes/pkg/apis/policy/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" +) + +// podDisruptionBudgetStrategy implements verification logic for PodDisruptionBudgets. +type podDisruptionBudgetStrategy struct { + runtime.ObjectTyper + api.NameGenerator +} + +// Strategy is the default logic that applies when creating and updating PodDisruptionBudget objects. +var Strategy = podDisruptionBudgetStrategy{api.Scheme, api.SimpleNameGenerator} + +// NamespaceScoped returns true because all PodDisruptionBudget' need to be within a namespace. +func (podDisruptionBudgetStrategy) NamespaceScoped() bool { + return true +} + +// PrepareForCreate clears the status of an PodDisruptionBudget before creation. +func (podDisruptionBudgetStrategy) PrepareForCreate(obj runtime.Object) { + podDisruptionBudget := obj.(*policy.PodDisruptionBudget) + // create cannot set status + podDisruptionBudget.Status = policy.PodDisruptionBudgetStatus{} + + podDisruptionBudget.Generation = 1 +} + +// PrepareForUpdate clears fields that are not allowed to be set by end users on update. +func (podDisruptionBudgetStrategy) PrepareForUpdate(obj, old runtime.Object) { + newPodDisruptionBudget := obj.(*policy.PodDisruptionBudget) + oldPodDisruptionBudget := old.(*policy.PodDisruptionBudget) + // Update is not allowed to set status + newPodDisruptionBudget.Status = oldPodDisruptionBudget.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(oldPodDisruptionBudget.Spec, newPodDisruptionBudget.Spec) { + newPodDisruptionBudget.Generation = oldPodDisruptionBudget.Generation + 1 + } +} + +// Validate validates a new PodDisruptionBudget. +func (podDisruptionBudgetStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { + podDisruptionBudget := obj.(*policy.PodDisruptionBudget) + return validation.ValidatePodDisruptionBudget(podDisruptionBudget) +} + +// Canonicalize normalizes the object after validation. +func (podDisruptionBudgetStrategy) Canonicalize(obj runtime.Object) { +} + +// AllowCreateOnUpdate is true for PodDisruptionBudget; this means you may create one with a PUT request. +func (podDisruptionBudgetStrategy) AllowCreateOnUpdate() bool { + return false +} + +// ValidateUpdate is the default update validation for an end user. +func (podDisruptionBudgetStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { + validationErrorList := validation.ValidatePodDisruptionBudget(obj.(*policy.PodDisruptionBudget)) + updateErrorList := validation.ValidatePodDisruptionBudgetUpdate(obj.(*policy.PodDisruptionBudget), old.(*policy.PodDisruptionBudget)) + return append(validationErrorList, updateErrorList...) +} + +// AllowUnconditionalUpdate is the default update policy for PodDisruptionBudget objects. +func (podDisruptionBudgetStrategy) AllowUnconditionalUpdate() bool { + return true +} + +// PodDisruptionBudgetToSelectableFields returns a field set that represents the object. +func PodDisruptionBudgetToSelectableFields(podDisruptionBudget *policy.PodDisruptionBudget) fields.Set { + return generic.ObjectMetaFieldsSet(podDisruptionBudget.ObjectMeta, true) +} + +// MatchPodDisruptionBudget 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 MatchPodDisruptionBudget(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) { + podDisruptionBudget, ok := obj.(*policy.PodDisruptionBudget) + if !ok { + return nil, nil, fmt.Errorf("given object is not a PodDisruptionBudget.") + } + return labels.Set(podDisruptionBudget.ObjectMeta.Labels), PodDisruptionBudgetToSelectableFields(podDisruptionBudget), nil + }, + } +} + +type podDisruptionBudgetStatusStrategy struct { + podDisruptionBudgetStrategy +} + +var StatusStrategy = podDisruptionBudgetStatusStrategy{Strategy} + +// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status +func (podDisruptionBudgetStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { + newPodDisruptionBudget := obj.(*policy.PodDisruptionBudget) + oldPodDisruptionBudget := old.(*policy.PodDisruptionBudget) + // status changes are not allowed to update spec + newPodDisruptionBudget.Spec = oldPodDisruptionBudget.Spec +} + +// ValidateUpdate is the default update validation for an end user updating status +func (podDisruptionBudgetStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { + // TODO: Validate status updates. + return field.ErrorList{} + // return validation.ValidatePodDisruptionBudgetStatusUpdate(obj.(*policy.PodDisruptionBudget), old.(*policy.PodDisruptionBudget)) +} diff --git a/pkg/registry/poddisruptionbudget/strategy_test.go b/pkg/registry/poddisruptionbudget/strategy_test.go new file mode 100644 index 00000000000..6469af3b025 --- /dev/null +++ b/pkg/registry/poddisruptionbudget/strategy_test.go @@ -0,0 +1,134 @@ +/* +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 poddisruptionbudget + +import ( + "testing" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/policy" + "k8s.io/kubernetes/pkg/util/intstr" +) + +func TestPodDisruptionBudgetStrategy(t *testing.T) { + ctx := api.NewDefaultContext() + if !Strategy.NamespaceScoped() { + t.Errorf("PodDisruptionBudget must be namespace scoped") + } + if Strategy.AllowCreateOnUpdate() { + t.Errorf("PodDisruptionBudget should not allow create on update") + } + + validSelector := map[string]string{"a": "b"} + pdb := &policy.PodDisruptionBudget{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, + Spec: policy.PodDisruptionBudgetSpec{ + MinAvailable: intstr.FromInt(3), + Selector: &unversioned.LabelSelector{MatchLabels: validSelector}, + }, + } + + Strategy.PrepareForCreate(pdb) + errs := Strategy.Validate(ctx, pdb) + if len(errs) != 0 { + t.Errorf("Unexpected error validating %v", errs) + } + + newPdb := &policy.PodDisruptionBudget{ + ObjectMeta: api.ObjectMeta{Name: pdb.Name, Namespace: pdb.Namespace}, + Spec: pdb.Spec, + Status: policy.PodDisruptionBudgetStatus{ + PodDisruptionAllowed: true, + CurrentHealthy: 3, + DesiredHealthy: 3, + ExpectedPods: 3, + }, + } + + // Nothing in Spec changes: OK + Strategy.PrepareForUpdate(newPdb, pdb) + errs = Strategy.ValidateUpdate(ctx, newPdb, pdb) + if len(errs) != 0 { + t.Errorf("Unexpected error updating PodDisruptionBudget.") + } + + // Changing the selector? No. + newPdb.Spec.Selector = &unversioned.LabelSelector{MatchLabels: map[string]string{"a": "bar"}} + Strategy.PrepareForUpdate(newPdb, pdb) + errs = Strategy.ValidateUpdate(ctx, newPdb, pdb) + if len(errs) == 0 { + t.Errorf("Expected a validation error since updates are disallowed on poddisruptionbudgets.") + } + newPdb.Spec.Selector = pdb.Spec.Selector + + // Changing MinAvailable? Also no. + newPdb.Spec.MinAvailable = intstr.FromString("28%") + Strategy.PrepareForUpdate(newPdb, pdb) + errs = Strategy.ValidateUpdate(ctx, newPdb, pdb) + if len(errs) == 0 { + t.Errorf("Expected a validation error since updates are disallowed on poddisruptionbudgets.") + } +} + +func TestPodDisruptionBudgetStatusStrategy(t *testing.T) { + ctx := api.NewDefaultContext() + if !StatusStrategy.NamespaceScoped() { + t.Errorf("PodDisruptionBudgetStatus must be namespace scoped") + } + if StatusStrategy.AllowCreateOnUpdate() { + t.Errorf("PodDisruptionBudgetStatus should not allow create on update") + } + validSelector := map[string]string{"a": "b"} + oldPdb := &policy.PodDisruptionBudget{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault, ResourceVersion: "10"}, + Spec: policy.PodDisruptionBudgetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validSelector}, + MinAvailable: intstr.FromInt(3), + }, + Status: policy.PodDisruptionBudgetStatus{ + PodDisruptionAllowed: true, + CurrentHealthy: 3, + DesiredHealthy: 3, + ExpectedPods: 3, + }, + } + newPdb := &policy.PodDisruptionBudget{ + ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault, ResourceVersion: "9"}, + Spec: policy.PodDisruptionBudgetSpec{ + Selector: &unversioned.LabelSelector{MatchLabels: validSelector}, + MinAvailable: intstr.FromInt(2), + }, + Status: policy.PodDisruptionBudgetStatus{ + PodDisruptionAllowed: false, + CurrentHealthy: 2, + DesiredHealthy: 3, + ExpectedPods: 3, + }, + } + StatusStrategy.PrepareForUpdate(newPdb, oldPdb) + if newPdb.Status.CurrentHealthy != 2 { + t.Errorf("PodDisruptionBudget status updates should allow change of CurrentHealthy: %v", newPdb.Status.CurrentHealthy) + } + if newPdb.Spec.MinAvailable.IntValue() != 3 { + t.Errorf("PodDisruptionBudget status updates should not clobber spec: %v", newPdb.Spec) + } + errs := StatusStrategy.ValidateUpdate(ctx, newPdb, oldPdb) + if len(errs) != 0 { + t.Errorf("Unexpected error %v", errs) + } +} diff --git a/test/integration/framework/master_utils.go b/test/integration/framework/master_utils.go index 29af8f9843f..0dec3287e41 100644 --- a/test/integration/framework/master_utils.go +++ b/test/integration/framework/master_utils.go @@ -34,6 +34,7 @@ import ( "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/apiserver" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/record" @@ -178,6 +179,10 @@ func NewMasterConfig() *master.Config { unversioned.GroupResource{Group: extensions.GroupName, Resource: genericapiserver.AllResources}, "", NewSingleContentTypeSerializer(api.Scheme, testapi.Extensions.Codec(), runtime.ContentTypeJSON)) + storageFactory.SetSerializer( + unversioned.GroupResource{Group: policy.GroupName, Resource: genericapiserver.AllResources}, + "", + NewSingleContentTypeSerializer(api.Scheme, testapi.Policy.Codec(), runtime.ContentTypeJSON)) return &master.Config{ Config: &genericapiserver.Config{