From 196d663b408cd85556fd2012feeaa56aa14e28f1 Mon Sep 17 00:00:00 2001 From: jianhuiz Date: Tue, 20 Dec 2016 18:03:20 -0800 Subject: [PATCH] register batch/jobs to federated-apiserver --- federation/apis/openapi-spec/swagger.json | 1103 +++++++++++++++++ federation/cmd/federation-apiserver/app/BUILD | 4 + .../cmd/federation-apiserver/app/batch.go | 52 + .../cmd/federation-apiserver/app/server.go | 1 + pkg/registry/batch/job/etcd/etcd.go | 15 + pkg/registry/batch/job/etcd/etcd_test.go | 42 +- test/integration/federation/BUILD | 1 + test/integration/federation/server_test.go | 29 + 8 files changed, 1226 insertions(+), 21 deletions(-) create mode 100644 federation/cmd/federation-apiserver/app/batch.go diff --git a/federation/apis/openapi-spec/swagger.json b/federation/apis/openapi-spec/swagger.json index 625efbed4d4..2ccf17b6240 100644 --- a/federation/apis/openapi-spec/swagger.json +++ b/federation/apis/openapi-spec/swagger.json @@ -3883,6 +3883,970 @@ } } }, + "/apis/batch/": { + "get": { + "description": "get information of a group", + "consumes": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch" + ], + "operationId": "getBatchAPIGroup", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.APIGroup" + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/apis/batch/v1/": { + "get": { + "description": "get available resources", + "consumes": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "getBatchV1APIResources", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.APIResourceList" + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/apis/batch/v1/jobs": { + "get": { + "description": "list or watch objects of kind Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "listBatchV1JobForAllNamespaces", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.JobList" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "name": "fieldSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "name": "labelSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "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. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "name": "resourceVersion", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "Timeout for the list/watch call.", + "name": "timeoutSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "name": "watch", + "in": "query" + } + ] + }, + "/apis/batch/v1/namespaces/{namespace}/jobs": { + "get": { + "description": "list or watch objects of kind Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "listBatchV1NamespacedJob", + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "name": "fieldSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "name": "labelSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "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. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "name": "resourceVersion", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "Timeout for the list/watch call.", + "name": "timeoutSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "name": "watch", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.JobList" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "post": { + "description": "create a Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "createBatchV1NamespacedJob", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1.Job" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.Job" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "delete": { + "description": "delete collection of Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "deleteBatchV1CollectionNamespacedJob", + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "name": "fieldSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "name": "labelSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "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. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "name": "resourceVersion", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "Timeout for the list/watch call.", + "name": "timeoutSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "name": "watch", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.Status" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "object name and auth scope, such as for teams and projects", + "name": "namespace", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + } + ] + }, + "/apis/batch/v1/namespaces/{namespace}/jobs/{name}": { + "get": { + "description": "read the specified Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "readBatchV1NamespacedJob", + "parameters": [ + { + "uniqueItems": true, + "type": "boolean", + "description": "Should the export be exact. Exact export maintains cluster-specific fields like 'Namespace'.", + "name": "exact", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Should this value be exported. Export strips fields that a user can not specify.", + "name": "export", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.Job" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "put": { + "description": "replace the specified Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "replaceBatchV1NamespacedJob", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1.Job" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.Job" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "delete": { + "description": "delete a Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "deleteBatchV1NamespacedJob", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1.DeleteOptions" + } + }, + { + "uniqueItems": true, + "type": "integer", + "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.", + "name": "gracePeriodSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "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.", + "name": "orphanDependents", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.Status" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "patch": { + "description": "partially update the specified Job", + "consumes": [ + "application/json-patch+json", + "application/merge-patch+json", + "application/strategic-merge-patch+json" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "patchBatchV1NamespacedJob", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1.Patch" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.Job" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "name of the Job", + "name": "name", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "object name and auth scope, such as for teams and projects", + "name": "namespace", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + } + ] + }, + "/apis/batch/v1/namespaces/{namespace}/jobs/{name}/status": { + "get": { + "description": "read status of the specified Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "readBatchV1NamespacedJobStatus", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.Job" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "put": { + "description": "replace status of the specified Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "replaceBatchV1NamespacedJobStatus", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1.Job" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.Job" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "patch": { + "description": "partially update status of the specified Job", + "consumes": [ + "application/json-patch+json", + "application/merge-patch+json", + "application/strategic-merge-patch+json" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "patchBatchV1NamespacedJobStatus", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1.Patch" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.Job" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "name of the Job", + "name": "name", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "object name and auth scope, such as for teams and projects", + "name": "namespace", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + } + ] + }, + "/apis/batch/v1/watch/jobs": { + "get": { + "description": "watch individual changes to a list of Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "watchBatchV1JobListForAllNamespaces", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/versioned.Event" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "name": "fieldSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "name": "labelSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "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. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "name": "resourceVersion", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "Timeout for the list/watch call.", + "name": "timeoutSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "name": "watch", + "in": "query" + } + ] + }, + "/apis/batch/v1/watch/namespaces/{namespace}/jobs": { + "get": { + "description": "watch individual changes to a list of Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "watchBatchV1NamespacedJobList", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/versioned.Event" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "name": "fieldSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "name": "labelSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "object name and auth scope, such as for teams and projects", + "name": "namespace", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "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. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "name": "resourceVersion", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "Timeout for the list/watch call.", + "name": "timeoutSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "name": "watch", + "in": "query" + } + ] + }, + "/apis/batch/v1/watch/namespaces/{namespace}/jobs/{name}": { + "get": { + "description": "watch changes to an object of kind Job", + "consumes": [ + "*/*" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v1" + ], + "operationId": "watchBatchV1NamespacedJob", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/versioned.Event" + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "parameters": [ + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "name": "fieldSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "name": "labelSelector", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "description": "name of the Job", + "name": "name", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "object name and auth scope, such as for teams and projects", + "name": "namespace", + "in": "path", + "required": true + }, + { + "uniqueItems": true, + "type": "string", + "description": "If 'true', then the output is pretty printed.", + "name": "pretty", + "in": "query" + }, + { + "uniqueItems": true, + "type": "string", + "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. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "name": "resourceVersion", + "in": "query" + }, + { + "uniqueItems": true, + "type": "integer", + "description": "Timeout for the list/watch call.", + "name": "timeoutSeconds", + "in": "query" + }, + { + "uniqueItems": true, + "type": "boolean", + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "name": "watch", + "in": "query" + } + ] + }, + "/apis/batch/v2alpha1/": { + "get": { + "description": "get available resources", + "consumes": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "schemes": [ + "https" + ], + "tags": [ + "batch_v2alpha1" + ], + "operationId": "getBatchV2alpha1APIResources", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.APIResourceList" + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, "/apis/extensions/": { "get": { "description": "get information of a group", @@ -9062,6 +10026,145 @@ } } }, + "v1.Job": { + "description": "Job represents the configuration of a single job.", + "properties": { + "metadata": { + "description": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata", + "$ref": "#/definitions/v1.ObjectMeta" + }, + "spec": { + "description": "Spec is a structure defining the expected behavior of a job. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status", + "$ref": "#/definitions/v1.JobSpec" + }, + "status": { + "description": "Status is a structure describing current status of a job. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status", + "$ref": "#/definitions/v1.JobStatus" + } + } + }, + "v1.JobCondition": { + "description": "JobCondition describes current state of a job.", + "required": [ + "type", + "status" + ], + "properties": { + "lastProbeTime": { + "description": "Last time the condition was checked.", + "$ref": "#/definitions/v1.Time" + }, + "lastTransitionTime": { + "description": "Last time the condition transit from one status to another.", + "$ref": "#/definitions/v1.Time" + }, + "message": { + "description": "Human readable message indicating details about last transition.", + "type": "string" + }, + "reason": { + "description": "(brief) reason for the condition's last transition.", + "type": "string" + }, + "status": { + "description": "Status of the condition, one of True, False, Unknown.", + "type": "string" + }, + "type": { + "description": "Type of job condition, Complete or Failed.", + "type": "string" + } + } + }, + "v1.JobList": { + "description": "JobList is a collection of jobs.", + "required": [ + "items" + ], + "properties": { + "items": { + "description": "Items is the list of Job.", + "type": "array", + "items": { + "$ref": "#/definitions/v1.Job" + } + }, + "metadata": { + "description": "Standard list metadata More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata", + "$ref": "#/definitions/v1.ListMeta" + } + } + }, + "v1.JobSpec": { + "description": "JobSpec describes how the job execution will look like.", + "required": [ + "template" + ], + "properties": { + "activeDeadlineSeconds": { + "description": "Optional duration in seconds relative to the startTime that the job may be active before the system tries to terminate it; value must be positive integer", + "type": "integer", + "format": "int64" + }, + "completions": { + "description": "Completions specifies the desired number of successfully finished pods the job should be run with. Setting to nil means that the success of any pod signals the success of all pods, and allows parallelism to have any positive value. Setting to 1 means that parallelism is limited to 1 and the success of that pod signals the success of the job. More info: http://kubernetes.io/docs/user-guide/jobs", + "type": "integer", + "format": "int32" + }, + "manualSelector": { + "description": "ManualSelector controls generation of pod labels and pod selectors. Leave `manualSelector` unset unless you are certain what you are doing. When false or unset, the system pick labels unique to this job and appends those labels to the pod template. When true, the user is responsible for picking unique labels and specifying the selector. Failure to pick a unique label may cause this and other jobs to not function correctly. However, You may see `manualSelector=true` in jobs that were created with the old `extensions/v1beta1` API. More info: http://releases.k8s.io/HEAD/docs/design/selector-generation.md", + "type": "boolean" + }, + "parallelism": { + "description": "Parallelism specifies the maximum desired number of pods the job should run at any given time. The actual number of pods running in steady state will be less than this number when ((.spec.completions - .status.successful) \u003c .spec.parallelism), i.e. when the work left to do is less than max parallelism. More info: http://kubernetes.io/docs/user-guide/jobs", + "type": "integer", + "format": "int32" + }, + "selector": { + "description": "Selector is a label query over pods that should match the pod count. Normally, the system sets this field for you. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors", + "$ref": "#/definitions/v1.LabelSelector" + }, + "template": { + "description": "Template is the object that describes the pod that will be created when executing a job. More info: http://kubernetes.io/docs/user-guide/jobs", + "$ref": "#/definitions/v1.PodTemplateSpec" + } + } + }, + "v1.JobStatus": { + "description": "JobStatus represents the current state of a Job.", + "properties": { + "active": { + "description": "Active is the number of actively running pods.", + "type": "integer", + "format": "int32" + }, + "completionTime": { + "description": "CompletionTime represents time when the job was completed. It is not guaranteed to be set in happens-before order across separate operations. It is represented in RFC3339 form and is in UTC.", + "$ref": "#/definitions/v1.Time" + }, + "conditions": { + "description": "Conditions represent the latest available observations of an object's current state. More info: http://kubernetes.io/docs/user-guide/jobs", + "type": "array", + "items": { + "$ref": "#/definitions/v1.JobCondition" + } + }, + "failed": { + "description": "Failed is the number of pods which reached Phase Failed.", + "type": "integer", + "format": "int32" + }, + "startTime": { + "description": "StartTime represents time when the job was acknowledged by the Job Manager. It is not guaranteed to be set in happens-before order across separate operations. It is represented in RFC3339 form and is in UTC.", + "$ref": "#/definitions/v1.Time" + }, + "succeeded": { + "description": "Succeeded is the number of pods which reached Phase Succeeded.", + "type": "integer", + "format": "int32" + } + } + }, "v1.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": { diff --git a/federation/cmd/federation-apiserver/app/BUILD b/federation/cmd/federation-apiserver/app/BUILD index c1273b8689b..08f4ebc006b 100644 --- a/federation/cmd/federation-apiserver/app/BUILD +++ b/federation/cmd/federation-apiserver/app/BUILD @@ -10,6 +10,7 @@ load( go_library( name = "go_default_library", srcs = [ + "batch.go", "core.go", "extensions.go", "federation.go", @@ -30,6 +31,8 @@ go_library( "//pkg/api/install:go_default_library", "//pkg/api/rest:go_default_library", "//pkg/apimachinery/registered:go_default_library", + "//pkg/apis/batch:go_default_library", + "//pkg/apis/batch/install:go_default_library", "//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions/install:go_default_library", "//pkg/apiserver/authenticator:go_default_library", @@ -40,6 +43,7 @@ go_library( "//pkg/genericapiserver:go_default_library", "//pkg/genericapiserver/authorizer:go_default_library", "//pkg/genericapiserver/filters:go_default_library", + "//pkg/registry/batch/job/etcd:go_default_library", "//pkg/registry/cachesize:go_default_library", "//pkg/registry/core/configmap/etcd:go_default_library", "//pkg/registry/core/event/etcd:go_default_library", diff --git a/federation/cmd/federation-apiserver/app/batch.go b/federation/cmd/federation-apiserver/app/batch.go new file mode 100644 index 00000000000..3b0c3c22f97 --- /dev/null +++ b/federation/cmd/federation-apiserver/app/batch.go @@ -0,0 +1,52 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package app + +import ( + "github.com/golang/glog" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/rest" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/batch" + _ "k8s.io/kubernetes/pkg/apis/batch/install" + "k8s.io/kubernetes/pkg/genericapiserver" + jobetcd "k8s.io/kubernetes/pkg/registry/batch/job/etcd" + "k8s.io/kubernetes/pkg/registry/generic" +) + +func installBatchAPIs(g *genericapiserver.GenericAPIServer, optsGetter generic.RESTOptionsGetter) { + jobStorage := jobetcd.NewStorage(optsGetter) + + batchResources := map[string]rest.Storage{ + "jobs": jobStorage.Job, + "jobs/status": jobStorage.Status, + } + batchGroupMeta := registered.GroupOrDie(batch.GroupName) + apiGroupInfo := genericapiserver.APIGroupInfo{ + GroupMeta: *batchGroupMeta, + VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ + "v1": batchResources, + }, + OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, + Scheme: api.Scheme, + ParameterCodec: api.ParameterCodec, + NegotiatedSerializer: api.Codecs, + } + if err := g.InstallAPIGroup(&apiGroupInfo); err != nil { + glog.Fatalf("Error in registering group versions: %v", err) + } +} diff --git a/federation/cmd/federation-apiserver/app/server.go b/federation/cmd/federation-apiserver/app/server.go index 955ddfff7ae..4cca4461d99 100644 --- a/federation/cmd/federation-apiserver/app/server.go +++ b/federation/cmd/federation-apiserver/app/server.go @@ -207,6 +207,7 @@ func Run(s *options.ServerRunOptions) error { installFederationAPIs(m, restOptionsFactory) installCoreAPIs(s, m, restOptionsFactory) installExtensionsAPIs(m, restOptionsFactory) + installBatchAPIs(m, restOptionsFactory) sharedInformers.Start(wait.NeverStop) m.PrepareRun().Run(wait.NeverStop) diff --git a/pkg/registry/batch/job/etcd/etcd.go b/pkg/registry/batch/job/etcd/etcd.go index 7e77e13fca0..1bf156a8e29 100644 --- a/pkg/registry/batch/job/etcd/etcd.go +++ b/pkg/registry/batch/job/etcd/etcd.go @@ -27,6 +27,21 @@ import ( "k8s.io/kubernetes/pkg/runtime" ) +// JobStorage includes dummy storage for Job. +type JobStorage struct { + Job *REST + Status *StatusREST +} + +func NewStorage(optsGetter generic.RESTOptionsGetter) JobStorage { + jobRest, jobStatusRest := NewREST(optsGetter) + + return JobStorage{ + Job: jobRest, + Status: jobStatusRest, + } +} + // REST implements a RESTStorage for jobs against etcd type REST struct { *genericregistry.Store diff --git a/pkg/registry/batch/job/etcd/etcd_test.go b/pkg/registry/batch/job/etcd/etcd_test.go index 0c262f07b6e..6b34f476e82 100644 --- a/pkg/registry/batch/job/etcd/etcd_test.go +++ b/pkg/registry/batch/job/etcd/etcd_test.go @@ -30,7 +30,7 @@ import ( etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" ) -func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) { +func newStorage(t *testing.T) (*JobStorage, *etcdtesting.EtcdTestServer) { etcdStorage, server := registrytest.NewEtcdStorage(t, batch.GroupName) restOptions := generic.RESTOptions{ StorageConfig: etcdStorage, @@ -38,8 +38,8 @@ func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) DeleteCollectionWorkers: 1, ResourcePrefix: "jobs", } - jobStorage, statusStorage := NewREST(restOptions) - return jobStorage, statusStorage, server + jobStorage := NewStorage(restOptions) + return &jobStorage, server } func validNewJob() *batch.Job { @@ -78,10 +78,10 @@ func validNewJob() *batch.Job { } func TestCreate(t *testing.T) { - storage, _, server := newStorage(t) + storage, server := newStorage(t) defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) + defer storage.Job.Store.DestroyFunc() + test := registrytest.New(t, storage.Job.Store) validJob := validNewJob() validJob.ObjectMeta = api.ObjectMeta{} test.TestCreate( @@ -99,10 +99,10 @@ func TestCreate(t *testing.T) { } func TestUpdate(t *testing.T) { - storage, _, server := newStorage(t) + storage, server := newStorage(t) defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) + defer storage.Job.Store.DestroyFunc() + test := registrytest.New(t, storage.Job.Store) two := int32(2) test.TestUpdate( // valid @@ -128,34 +128,34 @@ func TestUpdate(t *testing.T) { } func TestDelete(t *testing.T) { - storage, _, server := newStorage(t) + storage, server := newStorage(t) defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) + defer storage.Job.Store.DestroyFunc() + test := registrytest.New(t, storage.Job.Store) test.TestDelete(validNewJob()) } func TestGet(t *testing.T) { - storage, _, server := newStorage(t) + storage, server := newStorage(t) defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) + defer storage.Job.Store.DestroyFunc() + test := registrytest.New(t, storage.Job.Store) test.TestGet(validNewJob()) } func TestList(t *testing.T) { - storage, _, server := newStorage(t) + storage, server := newStorage(t) defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) + defer storage.Job.Store.DestroyFunc() + test := registrytest.New(t, storage.Job.Store) test.TestList(validNewJob()) } func TestWatch(t *testing.T) { - storage, _, server := newStorage(t) + storage, server := newStorage(t) defer server.Terminate(t) - defer storage.Store.DestroyFunc() - test := registrytest.New(t, storage.Store) + defer storage.Job.Store.DestroyFunc() + test := registrytest.New(t, storage.Job.Store) test.TestWatch( validNewJob(), // matching labels diff --git a/test/integration/federation/BUILD b/test/integration/federation/BUILD index 69a0701b69c..382c27d01ac 100644 --- a/test/integration/federation/BUILD +++ b/test/integration/federation/BUILD @@ -16,6 +16,7 @@ go_test( "//federation/cmd/federation-apiserver/app:go_default_library", "//federation/cmd/federation-apiserver/app/options:go_default_library", "//pkg/api/v1:go_default_library", + "//pkg/apis/batch/v1:go_default_library", "//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/apis/meta/v1:go_default_library", "//pkg/runtime/schema:go_default_library", diff --git a/test/integration/federation/server_test.go b/test/integration/federation/server_test.go index f4da7cbfb25..5a676f49eef 100644 --- a/test/integration/federation/server_test.go +++ b/test/integration/federation/server_test.go @@ -31,6 +31,7 @@ import ( "k8s.io/kubernetes/federation/cmd/federation-apiserver/app" "k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options" "k8s.io/kubernetes/pkg/api/v1" + batch_v1 "k8s.io/kubernetes/pkg/apis/batch/v1" ext_v1b1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/runtime/schema" @@ -42,6 +43,7 @@ var serverIP = fmt.Sprintf("http://localhost:%v", insecurePort) var groupVersions = []schema.GroupVersion{ fed_v1b1.SchemeGroupVersion, ext_v1b1.SchemeGroupVersion, + batch_v1.SchemeGroupVersion, } func TestRun(t *testing.T) { @@ -211,6 +213,7 @@ func testAPIResourceList(t *testing.T) { testFederationResourceList(t) testCoreResourceList(t) testExtensionsResourceList(t) + testBatchResourceList(t) } func testFederationResourceList(t *testing.T) { @@ -344,3 +347,29 @@ func testExtensionsResourceList(t *testing.T) { assert.True(t, found.Namespaced) found = findResource(apiResourceList.APIResources, "deployments/rollback") } + +func testBatchResourceList(t *testing.T) { + serverURL := serverIP + "/apis/" + batch_v1.SchemeGroupVersion.String() + contents, err := readResponse(serverURL) + if err != nil { + t.Fatalf("%v", err) + } + var apiResourceList metav1.APIResourceList + err = json.Unmarshal(contents, &apiResourceList) + if err != nil { + t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) + } + // empty APIVersion for extensions group + assert.Equal(t, "v1", apiResourceList.APIVersion) + assert.Equal(t, batch_v1.SchemeGroupVersion.String(), apiResourceList.GroupVersion) + // Assert that there are exactly this number of resources. + assert.Equal(t, 2, len(apiResourceList.APIResources)) + + // Verify jobs + found := findResource(apiResourceList.APIResources, "jobs") + assert.NotNil(t, found) + assert.True(t, found.Namespaced) + found = findResource(apiResourceList.APIResources, "jobs/status") + assert.NotNil(t, found) + assert.True(t, found.Namespaced) +}