Move internal types of job from pkg/apis/extensions to pkg/apis/batch

pull/6/head
Maciej Szulik 2016-04-18 17:44:19 +02:00
parent c5df0bf23e
commit a3b4447305
40 changed files with 1004 additions and 812 deletions

View File

@ -32,7 +32,7 @@ import (
var ( var (
test = flag.BoolP("test", "t", false, "set this flag to generate the client code for the testdata") test = flag.BoolP("test", "t", false, "set this flag to generate the client code for the testdata")
inputVersions = flag.StringSlice("input", []string{"api/", "extensions/"}, "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\". Default to \"api/,extensions\"") inputVersions = flag.StringSlice("input", []string{"api/", "extensions/", "batch/"}, "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\". Default to \"api/,extensions/,batch/\"")
clientsetName = flag.StringP("clientset-name", "n", "internalclientset", "the name of the generated clientset package.") clientsetName = flag.StringP("clientset-name", "n", "internalclientset", "the name of the generated clientset package.")
clientsetPath = flag.String("clientset-path", "k8s.io/kubernetes/pkg/client/clientset_generated/", "the generated clientset will be output to <clientset-path>/<clientset-name>. Default to \"k8s.io/kubernetes/pkg/client/clientset_generated/\"") clientsetPath = flag.String("clientset-path", "k8s.io/kubernetes/pkg/client/clientset_generated/", "the generated clientset will be output to <clientset-path>/<clientset-name>. Default to \"k8s.io/kubernetes/pkg/client/clientset_generated/\"")
clientsetOnly = flag.Bool("clientset-only", false, "when set, client-gen only generates the clientset shell, without generating the individual typed clients") clientsetOnly = flag.Bool("clientset-only", false, "when set, client-gen only generates the clientset shell, without generating the individual typed clients")

View File

@ -60,6 +60,7 @@ func DefaultNameSystem() string {
var fallbackPackages = []string{ var fallbackPackages = []string{
"k8s.io/kubernetes/pkg/api/unversioned", "k8s.io/kubernetes/pkg/api/unversioned",
"k8s.io/kubernetes/pkg/apis/extensions", "k8s.io/kubernetes/pkg/apis/extensions",
"k8s.io/kubernetes/pkg/apis/batch",
} }
func getInternalTypeFor(context *generator.Context, t *types.Type) (*types.Type, bool) { func getInternalTypeFor(context *generator.Context, t *types.Type) (*types.Type, bool) {

View File

@ -29,6 +29,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
expvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" expvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation"
"k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/capabilities"
@ -109,7 +110,7 @@ func validateObject(obj runtime.Object) (errors field.ErrorList) {
t.Namespace = api.NamespaceDefault t.Namespace = api.NamespaceDefault
} }
errors = expvalidation.ValidateDeployment(t) errors = expvalidation.ValidateDeployment(t)
case *extensions.Job: case *batch.Job:
if t.Namespace == "" { if t.Namespace == "" {
t.Namespace = api.NamespaceDefault t.Namespace = api.NamespaceDefault
} }
@ -237,7 +238,7 @@ func TestExampleObjectSchemas(t *testing.T) {
"../docs/user-guide": { "../docs/user-guide": {
"multi-pod": nil, "multi-pod": nil,
"pod": &api.Pod{}, "pod": &api.Pod{},
"job": &extensions.Job{}, "job": &batch.Job{},
"ingress": &extensions.Ingress{}, "ingress": &extensions.Ingress{},
"nginx-deployment": &extensions.Deployment{}, "nginx-deployment": &extensions.Deployment{},
"new-nginx-deployment": &extensions.Deployment{}, "new-nginx-deployment": &extensions.Deployment{},
@ -405,12 +406,12 @@ func TestExampleObjectSchemas(t *testing.T) {
"javaweb-2": &api.Pod{}, "javaweb-2": &api.Pod{},
}, },
"../examples/job/work-queue-1": { "../examples/job/work-queue-1": {
"job": &extensions.Job{}, "job": &batch.Job{},
}, },
"../examples/job/work-queue-2": { "../examples/job/work-queue-2": {
"redis-pod": &api.Pod{}, "redis-pod": &api.Pod{},
"redis-service": &api.Service{}, "redis-service": &api.Service{},
"job": &extensions.Job{}, "job": &batch.Job{},
}, },
"../examples/azure_file": { "../examples/azure_file": {
"azure": &api.Pod{}, "azure": &api.Pod{},

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
@ -156,7 +157,7 @@ func FuzzerFor(t *testing.T, version unversioned.GroupVersion, src rand.Source)
j.RollingUpdate = &rollingUpdate j.RollingUpdate = &rollingUpdate
} }
}, },
func(j *extensions.JobSpec, c fuzz.Continue) { func(j *batch.JobSpec, c fuzz.Continue) {
c.FuzzNoCustom(j) // fuzz self without calling this function again c.FuzzNoCustom(j) // fuzz self without calling this function again
completions := int(c.Rand.Int31()) completions := int(c.Rand.Int31())
parallelism := int(c.Rand.Int31()) parallelism := int(c.Rand.Int31())

View File

@ -19,7 +19,6 @@ package batch
import ( import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
) )
@ -47,8 +46,11 @@ func AddToScheme(scheme *runtime.Scheme) {
// Adds the list of known types to api.Scheme. // Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) { func addKnownTypes(scheme *runtime.Scheme) {
scheme.AddKnownTypes(SchemeGroupVersion, scheme.AddKnownTypes(SchemeGroupVersion,
&extensions.Job{}, &Job{},
&extensions.JobList{}, &JobList{},
&api.ListOptions{}, &api.ListOptions{},
) )
} }
func (obj *Job) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *JobList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }

143
pkg/apis/batch/types.go Normal file
View File

@ -0,0 +1,143 @@
/*
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 batch
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
)
// +genclient=true
// Job represents the configuration of a single job.
type Job struct {
unversioned.TypeMeta `json:",inline"`
// Standard object's metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
api.ObjectMeta `json:"metadata,omitempty"`
// 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
Spec JobSpec `json:"spec,omitempty"`
// 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
Status JobStatus `json:"status,omitempty"`
}
// JobList is a collection of jobs.
type JobList struct {
unversioned.TypeMeta `json:",inline"`
// Standard list metadata
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
unversioned.ListMeta `json:"metadata,omitempty"`
// Items is the list of Job.
Items []Job `json:"items"`
}
// JobSpec describes how the job execution will look like.
type JobSpec struct {
// 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) < .spec.parallelism),
// i.e. when the work left to do is less than max parallelism.
Parallelism *int `json:"parallelism,omitempty"`
// 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.
Completions *int `json:"completions,omitempty"`
// 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
ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty"`
// Selector is a label query over pods that should match the pod count.
// Normally, the system sets this field for you.
Selector *unversioned.LabelSelector `json:"selector,omitempty"`
// 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.
ManualSelector *bool `json:"manualSelector,omitempty"`
// Template is the object that describes the pod that will be created when
// executing a job.
Template api.PodTemplateSpec `json:"template"`
}
// JobStatus represents the current state of a Job.
type JobStatus struct {
// Conditions represent the latest available observations of an object's current state.
Conditions []JobCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
// 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.
StartTime *unversioned.Time `json:"startTime,omitempty"`
// 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.
CompletionTime *unversioned.Time `json:"completionTime,omitempty"`
// Active is the number of actively running pods.
Active int `json:"active,omitempty"`
// Succeeded is the number of pods which reached Phase Succeeded.
Succeeded int `json:"succeeded,omitempty"`
// Failed is the number of pods which reached Phase Failed.
Failed int `json:"failed,omitempty"`
}
type JobConditionType string
// These are valid conditions of a job.
const (
// JobComplete means the job has completed its execution.
JobComplete JobConditionType = "Complete"
// JobFailed means the job has failed its execution.
JobFailed JobConditionType = "Failed"
)
// JobCondition describes current state of a job.
type JobCondition struct {
// Type of job condition, Complete or Failed.
Type JobConditionType `json:"type"`
// Status of the condition, one of True, False, Unknown.
Status api.ConditionStatus `json:"status"`
// Last time the condition was checked.
LastProbeTime unversioned.Time `json:"lastProbeTime,omitempty"`
// Last time the condition transit from one status to another.
LastTransitionTime unversioned.Time `json:"lastTransitionTime,omitempty"`
// (brief) reason for the condition's last transition.
Reason string `json:"reason,omitempty"`
// Human readable message indicating details about last transition.
Message string `json:"message,omitempty"`
}

View File

@ -18,14 +18,22 @@ package v1
import ( import (
"fmt" "fmt"
"reflect"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
v1 "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
) )
func addConversionFuncs(scheme *runtime.Scheme) { func addConversionFuncs(scheme *runtime.Scheme) {
// Add non-generated conversion functions // Add non-generated conversion functions
err := scheme.AddConversionFuncs() err := scheme.AddConversionFuncs(
Convert_batch_JobSpec_To_v1_JobSpec,
Convert_v1_JobSpec_To_batch_JobSpec,
)
if err != nil { if err != nil {
// If one of the conversion functions is malformed, detect it immediately. // If one of the conversion functions is malformed, detect it immediately.
panic(err) panic(err)
@ -45,3 +53,91 @@ func addConversionFuncs(scheme *runtime.Scheme) {
panic(err) panic(err)
} }
} }
func Convert_batch_JobSpec_To_v1_JobSpec(in *batch.JobSpec, out *JobSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*batch.JobSpec))(in)
}
if in.Parallelism != nil {
out.Parallelism = new(int32)
*out.Parallelism = int32(*in.Parallelism)
} else {
out.Parallelism = nil
}
if in.Completions != nil {
out.Completions = new(int32)
*out.Completions = int32(*in.Completions)
} else {
out.Completions = nil
}
if in.ActiveDeadlineSeconds != nil {
out.ActiveDeadlineSeconds = new(int64)
*out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds
} else {
out.ActiveDeadlineSeconds = nil
}
// unable to generate simple pointer conversion for unversioned.LabelSelector -> v1.LabelSelector
if in.Selector != nil {
out.Selector = new(LabelSelector)
if err := Convert_unversioned_LabelSelector_To_v1_LabelSelector(in.Selector, out.Selector, s); err != nil {
return err
}
} else {
out.Selector = nil
}
if in.ManualSelector != nil {
out.ManualSelector = new(bool)
*out.ManualSelector = *in.ManualSelector
} else {
out.ManualSelector = nil
}
if err := v1.Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, &out.Template, s); err != nil {
return err
}
return nil
}
func Convert_v1_JobSpec_To_batch_JobSpec(in *JobSpec, out *batch.JobSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*JobSpec))(in)
}
if in.Parallelism != nil {
out.Parallelism = new(int)
*out.Parallelism = int(*in.Parallelism)
} else {
out.Parallelism = nil
}
if in.Completions != nil {
out.Completions = new(int)
*out.Completions = int(*in.Completions)
} else {
out.Completions = nil
}
if in.ActiveDeadlineSeconds != nil {
out.ActiveDeadlineSeconds = new(int64)
*out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds
} else {
out.ActiveDeadlineSeconds = nil
}
// unable to generate simple pointer conversion for v1.LabelSelector -> unversioned.LabelSelector
if in.Selector != nil {
out.Selector = new(unversioned.LabelSelector)
if err := Convert_v1_LabelSelector_To_unversioned_LabelSelector(in.Selector, out.Selector, s); err != nil {
return err
}
} else {
out.Selector = nil
}
if in.ManualSelector != nil {
out.ManualSelector = new(bool)
*out.ManualSelector = *in.ManualSelector
} else {
out.ManualSelector = nil
}
if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(&in.Template, &out.Template, s); err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,157 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
unversionedvalidation "k8s.io/kubernetes/pkg/api/unversioned/validation"
apivalidation "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/validation/field"
)
// TODO: generalize for other controller objects that will follow the same pattern, such as ReplicaSet and DaemonSet, and
// move to new location. Replace batch.Job with an interface.
//
// ValidateGeneratedSelector validates that the generated selector on a controller object match the controller object
// metadata, and the labels on the pod template are as generated.
func ValidateGeneratedSelector(obj *batch.Job) field.ErrorList {
allErrs := field.ErrorList{}
if obj.Spec.ManualSelector != nil && *obj.Spec.ManualSelector {
return allErrs
}
if obj.Spec.Selector == nil {
return allErrs // This case should already have been checked in caller. No need for more errors.
}
// If somehow uid was unset then we would get "controller-uid=" as the selector
// which is bad.
if obj.ObjectMeta.UID == "" {
allErrs = append(allErrs, field.Required(field.NewPath("metadata").Child("uid"), ""))
}
// If somehow uid was unset then we would get "controller-uid=" as the selector
// which is bad.
if obj.ObjectMeta.UID == "" {
allErrs = append(allErrs, field.Required(field.NewPath("metadata").Child("uid"), ""))
}
// If selector generation was requested, then expected labels must be
// present on pod template, and much match job's uid and name. The
// generated (not-manual) selectors/labels ensure no overlap with other
// controllers. The manual mode allows orphaning, adoption,
// backward-compatibility, and experimentation with new
// labeling/selection schemes. Automatic selector generation should
// have placed certain labels on the pod, but this could have failed if
// the user added coflicting labels. Validate that the expected
// generated ones are there.
allErrs = append(allErrs, apivalidation.ValidateHasLabel(obj.Spec.Template.ObjectMeta, field.NewPath("spec").Child("template").Child("metadata"), "controller-uid", string(obj.UID))...)
allErrs = append(allErrs, apivalidation.ValidateHasLabel(obj.Spec.Template.ObjectMeta, field.NewPath("spec").Child("template").Child("metadata"), "job-name", string(obj.Name))...)
expectedLabels := make(map[string]string)
expectedLabels["controller-uid"] = string(obj.UID)
expectedLabels["job-name"] = string(obj.Name)
// Whether manually or automatically generated, the selector of the job must match the pods it will produce.
if selector, err := unversioned.LabelSelectorAsSelector(obj.Spec.Selector); err == nil {
if !selector.Matches(labels.Set(expectedLabels)) {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("selector"), obj.Spec.Selector, "`selector` not auto-generated"))
}
}
return allErrs
}
func ValidateJob(job *batch.Job) field.ErrorList {
// Jobs and rcs have the same name validation
allErrs := apivalidation.ValidateObjectMeta(&job.ObjectMeta, true, apivalidation.ValidateReplicationControllerName, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateGeneratedSelector(job)...)
allErrs = append(allErrs, ValidateJobSpec(&job.Spec, field.NewPath("spec"))...)
return allErrs
}
func ValidateJobSpec(spec *batch.JobSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if spec.Parallelism != nil {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.Parallelism), fldPath.Child("parallelism"))...)
}
if spec.Completions != nil {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.Completions), fldPath.Child("completions"))...)
}
if spec.ActiveDeadlineSeconds != nil {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.ActiveDeadlineSeconds), fldPath.Child("activeDeadlineSeconds"))...)
}
if spec.Selector == nil {
allErrs = append(allErrs, field.Required(fldPath.Child("selector"), ""))
} else {
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...)
}
// Whether manually or automatically generated, the selector of the job must match the pods it will produce.
if selector, err := unversioned.LabelSelectorAsSelector(spec.Selector); err == nil {
labels := labels.Set(spec.Template.Labels)
if !selector.Matches(labels) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("template", "metadata", "labels"), spec.Template.Labels, "`selector` does not match template `labels`"))
}
}
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(&spec.Template, fldPath.Child("template"))...)
if spec.Template.Spec.RestartPolicy != api.RestartPolicyOnFailure &&
spec.Template.Spec.RestartPolicy != api.RestartPolicyNever {
allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"),
spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)}))
}
return allErrs
}
func ValidateJobStatus(status *batch.JobStatus, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.Active), fldPath.Child("active"))...)
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.Succeeded), fldPath.Child("succeeded"))...)
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.Failed), fldPath.Child("failed"))...)
return allErrs
}
func ValidateJobUpdate(job, oldJob *batch.Job) field.ErrorList {
allErrs := apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateJobSpecUpdate(job.Spec, oldJob.Spec, field.NewPath("spec"))...)
return allErrs
}
func ValidateJobUpdateStatus(job, oldJob *batch.Job) field.ErrorList {
allErrs := apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateJobStatusUpdate(job.Status, oldJob.Status)...)
return allErrs
}
func ValidateJobSpecUpdate(spec, oldSpec batch.JobSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateJobSpec(&spec, fldPath)...)
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Completions, oldSpec.Completions, fldPath.Child("completions"))...)
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Selector, oldSpec.Selector, fldPath.Child("selector"))...)
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Template, oldSpec.Template, fldPath.Child("template"))...)
return allErrs
}
func ValidateJobStatusUpdate(status, oldStatus batch.JobStatus) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateJobStatus(&status, field.NewPath("status"))...)
return allErrs
}

View File

@ -0,0 +1,297 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
"strings"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/types"
)
func TestValidateJob(t *testing.T) {
validManualSelector := &unversioned.LabelSelector{
MatchLabels: map[string]string{"a": "b"},
}
validGeneratedSelector := &unversioned.LabelSelector{
MatchLabels: map[string]string{"controller-uid": "1a2b3c", "job-name": "myjob"},
}
validPodTemplateSpecForManual := api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validManualSelector.MatchLabels,
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
}
validPodTemplateSpecForGenerated := api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validGeneratedSelector.MatchLabels,
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
}
successCases := map[string]batch.Job{
"manual selector": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: validPodTemplateSpecForManual,
},
},
"generated selector": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Selector: validGeneratedSelector,
ManualSelector: newBool(false),
Template: validPodTemplateSpecForGenerated,
},
},
}
for k, v := range successCases {
if errs := ValidateJob(&v); len(errs) != 0 {
t.Errorf("expected success for %s: %v", k, errs)
}
}
negative := -1
negative64 := int64(-1)
errorCases := map[string]batch.Job{
"spec.parallelism:must be greater than or equal to 0": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Parallelism: &negative,
ManualSelector: newBool(true),
Template: validPodTemplateSpecForGenerated,
},
},
"spec.completions:must be greater than or equal to 0": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Completions: &negative,
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: validPodTemplateSpecForGenerated,
},
},
"spec.activeDeadlineSeconds:must be greater than or equal to 0": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
ActiveDeadlineSeconds: &negative64,
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: validPodTemplateSpecForGenerated,
},
},
"spec.selector:Required value": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Template: validPodTemplateSpecForGenerated,
},
},
"spec.template.metadata.labels: Invalid value: {\"y\":\"z\"}: `selector` does not match template `labels`": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: map[string]string{"y": "z"},
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
},
},
},
"spec.template.metadata.labels: Invalid value: {\"controller-uid\":\"4d5e6f\"}: `selector` does not match template `labels`": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: map[string]string{"controller-uid": "4d5e6f"},
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
},
},
},
"spec.template.spec.restartPolicy: Unsupported value": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validManualSelector.MatchLabels,
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
},
},
},
}
for k, v := range errorCases {
errs := ValidateJob(&v)
if len(errs) == 0 {
t.Errorf("expected failure for %s", k)
} else {
s := strings.Split(k, ":")
err := errs[0]
if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
t.Errorf("unexpected error: %v, expected: %s", err, k)
}
}
}
}
func TestValidateJobUpdateStatus(t *testing.T) {
type testcase struct {
old batch.Job
update batch.Job
}
successCases := []testcase{
{
old: batch.Job{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Status: batch.JobStatus{
Active: 1,
Succeeded: 2,
Failed: 3,
},
},
update: batch.Job{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Status: batch.JobStatus{
Active: 1,
Succeeded: 1,
Failed: 3,
},
},
},
}
for _, successCase := range successCases {
successCase.old.ObjectMeta.ResourceVersion = "1"
successCase.update.ObjectMeta.ResourceVersion = "1"
if errs := ValidateJobUpdateStatus(&successCase.update, &successCase.old); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
errorCases := map[string]testcase{
"[status.active: Invalid value: -1: must be greater than or equal to 0, status.succeeded: Invalid value: -2: must be greater than or equal to 0]": {
old: batch.Job{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: api.NamespaceDefault,
ResourceVersion: "10",
},
Status: batch.JobStatus{
Active: 1,
Succeeded: 2,
Failed: 3,
},
},
update: batch.Job{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: api.NamespaceDefault,
ResourceVersion: "10",
},
Status: batch.JobStatus{
Active: -1,
Succeeded: -2,
Failed: 3,
},
},
},
}
for testName, errorCase := range errorCases {
errs := ValidateJobUpdateStatus(&errorCase.update, &errorCase.old)
if len(errs) == 0 {
t.Errorf("expected failure: %s", testName)
continue
}
if errs.ToAggregate().Error() != testName {
t.Errorf("expected '%s' got '%s'", errs.ToAggregate().Error(), testName)
}
}
}
func newBool(val bool) *bool {
p := new(bool)
*p = val
return p
}

View File

@ -19,6 +19,7 @@ package extensions
import ( import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
) )
@ -52,8 +53,8 @@ func addKnownTypes(scheme *runtime.Scheme) {
&DeploymentRollback{}, &DeploymentRollback{},
&HorizontalPodAutoscaler{}, &HorizontalPodAutoscaler{},
&HorizontalPodAutoscalerList{}, &HorizontalPodAutoscalerList{},
&Job{}, &batch.Job{},
&JobList{}, &batch.JobList{},
&ReplicationControllerDummy{}, &ReplicationControllerDummy{},
&Scale{}, &Scale{},
&ThirdPartyResource{}, &ThirdPartyResource{},
@ -78,8 +79,6 @@ func (obj *DeploymentList) GetObjectKind() unversioned.ObjectKind {
func (obj *DeploymentRollback) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } func (obj *DeploymentRollback) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *HorizontalPodAutoscaler) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } func (obj *HorizontalPodAutoscaler) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *HorizontalPodAutoscalerList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } func (obj *HorizontalPodAutoscalerList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *Job) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *JobList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ReplicationControllerDummy) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } func (obj *ReplicationControllerDummy) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *ThirdPartyResource) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } func (obj *ThirdPartyResource) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }

View File

@ -496,127 +496,6 @@ type ThirdPartyResourceDataList struct {
// +genclient=true // +genclient=true
// Job represents the configuration of a single job.
type Job struct {
unversioned.TypeMeta `json:",inline"`
// Standard object's metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
api.ObjectMeta `json:"metadata,omitempty"`
// 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
Spec JobSpec `json:"spec,omitempty"`
// 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
Status JobStatus `json:"status,omitempty"`
}
// JobList is a collection of jobs.
type JobList struct {
unversioned.TypeMeta `json:",inline"`
// Standard list metadata
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
unversioned.ListMeta `json:"metadata,omitempty"`
// Items is the list of Job.
Items []Job `json:"items"`
}
// JobSpec describes how the job execution will look like.
type JobSpec struct {
// 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) < .spec.parallelism),
// i.e. when the work left to do is less than max parallelism.
Parallelism *int `json:"parallelism,omitempty"`
// 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.
Completions *int `json:"completions,omitempty"`
// 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
ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty"`
// Selector is a label query over pods that should match the pod count.
// Normally, the system sets this field for you.
Selector *unversioned.LabelSelector `json:"selector,omitempty"`
// 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.
ManualSelector *bool `json:"manualSelector,omitempty"`
// Template is the object that describes the pod that will be created when
// executing a job.
Template api.PodTemplateSpec `json:"template"`
}
// JobStatus represents the current state of a Job.
type JobStatus struct {
// Conditions represent the latest available observations of an object's current state.
Conditions []JobCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
// 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.
StartTime *unversioned.Time `json:"startTime,omitempty"`
// 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.
CompletionTime *unversioned.Time `json:"completionTime,omitempty"`
// Active is the number of actively running pods.
Active int `json:"active,omitempty"`
// Succeeded is the number of pods which reached Phase Succeeded.
Succeeded int `json:"succeeded,omitempty"`
// Failed is the number of pods which reached Phase Failed.
Failed int `json:"failed,omitempty"`
}
type JobConditionType string
// These are valid conditions of a job.
const (
// JobComplete means the job has completed its execution.
JobComplete JobConditionType = "Complete"
// JobFailed means the job has failed its execution.
JobFailed JobConditionType = "Failed"
)
// JobCondition describes current state of a job.
type JobCondition struct {
// Type of job condition, Complete or Failed.
Type JobConditionType `json:"type"`
// Status of the condition, one of True, False, Unknown.
Status api.ConditionStatus `json:"status"`
// Last time the condition was checked.
LastProbeTime unversioned.Time `json:"lastProbeTime,omitempty"`
// Last time the condition transit from one status to another.
LastTransitionTime unversioned.Time `json:"lastTransitionTime,omitempty"`
// (brief) reason for the condition's last transition.
Reason string `json:"reason,omitempty"`
// Human readable message indicating details about last transition.
Message string `json:"message,omitempty"`
}
// +genclient=true
// Ingress is a collection of rules that allow inbound connections to reach the // Ingress is a collection of rules that allow inbound connections to reach the
// endpoints defined by a backend. An Ingress can be configured to give services // endpoints defined by a backend. An Ingress can be configured to give services
// externally-reachable urls, load balance traffic, terminate SSL, offer name // externally-reachable urls, load balance traffic, terminate SSL, offer name

View File

@ -23,6 +23,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
v1 "k8s.io/kubernetes/pkg/api/v1" v1 "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/conversion" "k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
@ -42,8 +43,9 @@ func addConversionFuncs(scheme *runtime.Scheme) {
Convert_v1beta1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment, Convert_v1beta1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment,
Convert_extensions_ReplicaSetSpec_To_v1beta1_ReplicaSetSpec, Convert_extensions_ReplicaSetSpec_To_v1beta1_ReplicaSetSpec,
Convert_v1beta1_ReplicaSetSpec_To_extensions_ReplicaSetSpec, Convert_v1beta1_ReplicaSetSpec_To_extensions_ReplicaSetSpec,
Convert_extensions_JobSpec_To_v1beta1_JobSpec, // batch
Convert_v1beta1_JobSpec_To_extensions_JobSpec, Convert_batch_JobSpec_To_v1beta1_JobSpec,
Convert_v1beta1_JobSpec_To_batch_JobSpec,
) )
if err != nil { if err != nil {
// If one of the conversion functions is malformed, detect it immediately. // If one of the conversion functions is malformed, detect it immediately.
@ -312,9 +314,9 @@ func Convert_v1beta1_ReplicaSetSpec_To_extensions_ReplicaSetSpec(in *ReplicaSetS
return nil return nil
} }
func Convert_extensions_JobSpec_To_v1beta1_JobSpec(in *extensions.JobSpec, out *JobSpec, s conversion.Scope) error { func Convert_batch_JobSpec_To_v1beta1_JobSpec(in *batch.JobSpec, out *JobSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.JobSpec))(in) defaulting.(func(*batch.JobSpec))(in)
} }
if in.Parallelism != nil { if in.Parallelism != nil {
out.Parallelism = new(int32) out.Parallelism = new(int32)
@ -364,7 +366,7 @@ func Convert_extensions_JobSpec_To_v1beta1_JobSpec(in *extensions.JobSpec, out *
return nil return nil
} }
func Convert_v1beta1_JobSpec_To_extensions_JobSpec(in *JobSpec, out *extensions.JobSpec, s conversion.Scope) error { func Convert_v1beta1_JobSpec_To_batch_JobSpec(in *JobSpec, out *batch.JobSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*JobSpec))(in) defaulting.(func(*JobSpec))(in)
} }

View File

@ -21,7 +21,7 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/batch"
versioned "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" versioned "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
) )
@ -55,7 +55,7 @@ func TestJobSpecConversion(t *testing.T) {
// Test internal -> v1beta1. // Test internal -> v1beta1.
for _, test := range tests { for _, test := range tests {
i := &extensions.JobSpec{ i := &batch.JobSpec{
ManualSelector: test.in, ManualSelector: test.in,
} }
v := versioned.JobSpec{} v := versioned.JobSpec{}
@ -72,7 +72,7 @@ func TestJobSpecConversion(t *testing.T) {
i := &versioned.JobSpec{ i := &versioned.JobSpec{
AutoSelector: test.in, AutoSelector: test.in,
} }
e := extensions.JobSpec{} e := batch.JobSpec{}
if err := api.Scheme.Convert(i, &e); err != nil { if err := api.Scheme.Convert(i, &e); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }

View File

@ -382,136 +382,6 @@ func ValidateThirdPartyResourceData(obj *extensions.ThirdPartyResourceData) fiel
return allErrs return allErrs
} }
// TODO: generalize for other controller objects that will follow the same pattern, such as ReplicaSet and DaemonSet, and
// move to new location. Replace extensions.Job with an interface.
//
// ValidateGeneratedSelector validates that the generated selector on a controller object match the controller object
// metadata, and the labels on the pod template are as generated.
func ValidateGeneratedSelector(obj *extensions.Job) field.ErrorList {
allErrs := field.ErrorList{}
if obj.Spec.ManualSelector != nil && *obj.Spec.ManualSelector {
return allErrs
}
if obj.Spec.Selector == nil {
return allErrs // This case should already have been checked in caller. No need for more errors.
}
// If somehow uid was unset then we would get "controller-uid=" as the selector
// which is bad.
if obj.ObjectMeta.UID == "" {
allErrs = append(allErrs, field.Required(field.NewPath("metadata").Child("uid"), ""))
}
// If somehow uid was unset then we would get "controller-uid=" as the selector
// which is bad.
if obj.ObjectMeta.UID == "" {
allErrs = append(allErrs, field.Required(field.NewPath("metadata").Child("uid"), ""))
}
// If selector generation was requested, then expected labels must be
// present on pod template, and much match job's uid and name. The
// generated (not-manual) selectors/labels ensure no overlap with other
// controllers. The manual mode allows orphaning, adoption,
// backward-compatibility, and experimentation with new
// labeling/selection schemes. Automatic selector generation should
// have placed certain labels on the pod, but this could have failed if
// the user added coflicting labels. Validate that the expected
// generated ones are there.
allErrs = append(allErrs, apivalidation.ValidateHasLabel(obj.Spec.Template.ObjectMeta, field.NewPath("spec").Child("template").Child("metadata"), "controller-uid", string(obj.UID))...)
allErrs = append(allErrs, apivalidation.ValidateHasLabel(obj.Spec.Template.ObjectMeta, field.NewPath("spec").Child("template").Child("metadata"), "job-name", string(obj.Name))...)
expectedLabels := make(map[string]string)
expectedLabels["controller-uid"] = string(obj.UID)
expectedLabels["job-name"] = string(obj.Name)
// Whether manually or automatically generated, the selector of the job must match the pods it will produce.
if selector, err := unversioned.LabelSelectorAsSelector(obj.Spec.Selector); err == nil {
if !selector.Matches(labels.Set(expectedLabels)) {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("selector"), obj.Spec.Selector, "`selector` not auto-generated"))
}
}
return allErrs
}
func ValidateJob(job *extensions.Job) field.ErrorList {
// Jobs and rcs have the same name validation
allErrs := apivalidation.ValidateObjectMeta(&job.ObjectMeta, true, apivalidation.ValidateReplicationControllerName, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateGeneratedSelector(job)...)
allErrs = append(allErrs, ValidateJobSpec(&job.Spec, field.NewPath("spec"))...)
return allErrs
}
func ValidateJobSpec(spec *extensions.JobSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if spec.Parallelism != nil {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.Parallelism), fldPath.Child("parallelism"))...)
}
if spec.Completions != nil {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.Completions), fldPath.Child("completions"))...)
}
if spec.ActiveDeadlineSeconds != nil {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.ActiveDeadlineSeconds), fldPath.Child("activeDeadlineSeconds"))...)
}
if spec.Selector == nil {
allErrs = append(allErrs, field.Required(fldPath.Child("selector"), ""))
} else {
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...)
}
// Whether manually or automatically generated, the selector of the job must match the pods it will produce.
if selector, err := unversioned.LabelSelectorAsSelector(spec.Selector); err == nil {
labels := labels.Set(spec.Template.Labels)
if !selector.Matches(labels) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("template", "metadata", "labels"), spec.Template.Labels, "`selector` does not match template `labels`"))
}
}
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(&spec.Template, fldPath.Child("template"))...)
if spec.Template.Spec.RestartPolicy != api.RestartPolicyOnFailure &&
spec.Template.Spec.RestartPolicy != api.RestartPolicyNever {
allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"),
spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)}))
}
return allErrs
}
func ValidateJobStatus(status *extensions.JobStatus, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.Active), fldPath.Child("active"))...)
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.Succeeded), fldPath.Child("succeeded"))...)
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.Failed), fldPath.Child("failed"))...)
return allErrs
}
func ValidateJobUpdate(job, oldJob *extensions.Job) field.ErrorList {
allErrs := apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateJobSpecUpdate(job.Spec, oldJob.Spec, field.NewPath("spec"))...)
return allErrs
}
func ValidateJobUpdateStatus(job, oldJob *extensions.Job) field.ErrorList {
allErrs := apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateJobStatusUpdate(job.Status, oldJob.Status)...)
return allErrs
}
func ValidateJobSpecUpdate(spec, oldSpec extensions.JobSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateJobSpec(&spec, fldPath)...)
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Completions, oldSpec.Completions, fldPath.Child("completions"))...)
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Selector, oldSpec.Selector, fldPath.Child("selector"))...)
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Template, oldSpec.Template, fldPath.Child("template"))...)
return allErrs
}
func ValidateJobStatusUpdate(status, oldStatus extensions.JobStatus) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateJobStatus(&status, field.NewPath("status"))...)
return allErrs
}
// ValidateIngress tests if required fields in the Ingress are set. // ValidateIngress tests if required fields in the Ingress are set.
func ValidateIngress(ingress *extensions.Ingress) field.ErrorList { func ValidateIngress(ingress *extensions.Ingress) field.ErrorList {
allErrs := apivalidation.ValidateObjectMeta(&ingress.ObjectMeta, true, ValidateIngressName, field.NewPath("metadata")) allErrs := apivalidation.ValidateObjectMeta(&ingress.ObjectMeta, true, ValidateIngressName, field.NewPath("metadata"))

View File

@ -25,7 +25,6 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/controller/podautoscaler" "k8s.io/kubernetes/pkg/controller/podautoscaler"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/intstr"
) )
@ -989,270 +988,6 @@ func TestValidateDeploymentRollback(t *testing.T) {
} }
} }
func TestValidateJob(t *testing.T) {
validManualSelector := &unversioned.LabelSelector{
MatchLabels: map[string]string{"a": "b"},
}
validGeneratedSelector := &unversioned.LabelSelector{
MatchLabels: map[string]string{"controller-uid": "1a2b3c", "job-name": "myjob"},
}
validPodTemplateSpecForManual := api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validManualSelector.MatchLabels,
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
}
validPodTemplateSpecForGenerated := api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validGeneratedSelector.MatchLabels,
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
}
successCases := map[string]extensions.Job{
"manual selector": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: extensions.JobSpec{
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: validPodTemplateSpecForManual,
},
},
"generated selector": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: extensions.JobSpec{
Selector: validGeneratedSelector,
ManualSelector: newBool(false),
Template: validPodTemplateSpecForGenerated,
},
},
}
for k, v := range successCases {
if errs := ValidateJob(&v); len(errs) != 0 {
t.Errorf("expected success for %s: %v", k, errs)
}
}
negative := -1
negative64 := int64(-1)
errorCases := map[string]extensions.Job{
"spec.parallelism:must be greater than or equal to 0": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: extensions.JobSpec{
Parallelism: &negative,
ManualSelector: newBool(true),
Template: validPodTemplateSpecForGenerated,
},
},
"spec.completions:must be greater than or equal to 0": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: extensions.JobSpec{
Completions: &negative,
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: validPodTemplateSpecForGenerated,
},
},
"spec.activeDeadlineSeconds:must be greater than or equal to 0": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: extensions.JobSpec{
ActiveDeadlineSeconds: &negative64,
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: validPodTemplateSpecForGenerated,
},
},
"spec.selector:Required value": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: extensions.JobSpec{
Template: validPodTemplateSpecForGenerated,
},
},
"spec.template.metadata.labels: Invalid value: {\"y\":\"z\"}: `selector` does not match template `labels`": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: extensions.JobSpec{
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: map[string]string{"y": "z"},
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
},
},
},
"spec.template.metadata.labels: Invalid value: {\"controller-uid\":\"4d5e6f\"}: `selector` does not match template `labels`": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: extensions.JobSpec{
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: map[string]string{"controller-uid": "4d5e6f"},
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyOnFailure,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
},
},
},
"spec.template.spec.restartPolicy: Unsupported value": {
ObjectMeta: api.ObjectMeta{
Name: "myjob",
Namespace: api.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: extensions.JobSpec{
Selector: validManualSelector,
ManualSelector: newBool(true),
Template: api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: validManualSelector.MatchLabels,
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
},
},
},
},
}
for k, v := range errorCases {
errs := ValidateJob(&v)
if len(errs) == 0 {
t.Errorf("expected failure for %s", k)
} else {
s := strings.Split(k, ":")
err := errs[0]
if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
t.Errorf("unexpected error: %v, expected: %s", err, k)
}
}
}
}
func TestValidateJobUpdateStatus(t *testing.T) {
type testcase struct {
old extensions.Job
update extensions.Job
}
successCases := []testcase{
{
old: extensions.Job{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Status: extensions.JobStatus{
Active: 1,
Succeeded: 2,
Failed: 3,
},
},
update: extensions.Job{
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
Status: extensions.JobStatus{
Active: 1,
Succeeded: 1,
Failed: 3,
},
},
},
}
for _, successCase := range successCases {
successCase.old.ObjectMeta.ResourceVersion = "1"
successCase.update.ObjectMeta.ResourceVersion = "1"
if errs := ValidateJobUpdateStatus(&successCase.update, &successCase.old); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
errorCases := map[string]testcase{
"[status.active: Invalid value: -1: must be greater than or equal to 0, status.succeeded: Invalid value: -2: must be greater than or equal to 0]": {
old: extensions.Job{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: api.NamespaceDefault,
ResourceVersion: "10",
},
Status: extensions.JobStatus{
Active: 1,
Succeeded: 2,
Failed: 3,
},
},
update: extensions.Job{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: api.NamespaceDefault,
ResourceVersion: "10",
},
Status: extensions.JobStatus{
Active: -1,
Succeeded: -2,
Failed: 3,
},
},
},
}
for testName, errorCase := range errorCases {
errs := ValidateJobUpdateStatus(&errorCase.update, &errorCase.old)
if len(errs) == 0 {
t.Errorf("expected failure: %s", testName)
continue
}
if errs.ToAggregate().Error() != testName {
t.Errorf("expected '%s' got '%s'", errs.ToAggregate().Error(), testName)
}
}
}
type ingressRules map[string]string type ingressRules map[string]string
func TestValidateIngress(t *testing.T) { func TestValidateIngress(t *testing.T) {

View File

@ -22,6 +22,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
) )
@ -474,7 +475,7 @@ type StoreToJobLister struct {
} }
// Exists checks if the given job exists in the store. // Exists checks if the given job exists in the store.
func (s *StoreToJobLister) Exists(job *extensions.Job) (bool, error) { func (s *StoreToJobLister) Exists(job *batch.Job) (bool, error) {
_, exists, err := s.Store.Get(job) _, exists, err := s.Store.Get(job)
if err != nil { if err != nil {
return false, err return false, err
@ -483,17 +484,17 @@ func (s *StoreToJobLister) Exists(job *extensions.Job) (bool, error) {
} }
// StoreToJobLister lists all jobs in the store. // StoreToJobLister lists all jobs in the store.
func (s *StoreToJobLister) List() (jobs extensions.JobList, err error) { func (s *StoreToJobLister) List() (jobs batch.JobList, err error) {
for _, c := range s.Store.List() { for _, c := range s.Store.List() {
jobs.Items = append(jobs.Items, *(c.(*extensions.Job))) jobs.Items = append(jobs.Items, *(c.(*batch.Job)))
} }
return jobs, nil return jobs, nil
} }
// GetPodJobs returns a list of jobs managing a pod. Returns an error only if no matching jobs are found. // GetPodJobs returns a list of jobs managing a pod. Returns an error only if no matching jobs are found.
func (s *StoreToJobLister) GetPodJobs(pod *api.Pod) (jobs []extensions.Job, err error) { func (s *StoreToJobLister) GetPodJobs(pod *api.Pod) (jobs []batch.Job, err error) {
var selector labels.Selector var selector labels.Selector
var job extensions.Job var job batch.Job
if len(pod.Labels) == 0 { if len(pod.Labels) == 0 {
err = fmt.Errorf("no jobs found for pod %v because it has no labels", pod.Name) err = fmt.Errorf("no jobs found for pod %v because it has no labels", pod.Name)
@ -501,7 +502,7 @@ func (s *StoreToJobLister) GetPodJobs(pod *api.Pod) (jobs []extensions.Job, err
} }
for _, m := range s.Store.List() { for _, m := range s.Store.List() {
job = *m.(*extensions.Job) job = *m.(*batch.Job)
if job.Namespace != pod.Namespace { if job.Namespace != pod.Namespace {
continue continue
} }

View File

@ -21,6 +21,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/sets"
@ -476,18 +477,18 @@ func TestStoreToJobLister(t *testing.T) {
store := NewStore(MetaNamespaceKeyFunc) store := NewStore(MetaNamespaceKeyFunc)
lister := StoreToJobLister{store} lister := StoreToJobLister{store}
testCases := []struct { testCases := []struct {
inJobs []*extensions.Job inJobs []*batch.Job
list func() ([]extensions.Job, error) list func() ([]batch.Job, error)
outJobNames sets.String outJobNames sets.String
expectErr bool expectErr bool
msg string msg string
}{ }{
// Basic listing // Basic listing
{ {
inJobs: []*extensions.Job{ inJobs: []*batch.Job{
{ObjectMeta: api.ObjectMeta{Name: "basic"}}, {ObjectMeta: api.ObjectMeta{Name: "basic"}},
}, },
list: func() ([]extensions.Job, error) { list: func() ([]batch.Job, error) {
list, err := lister.List() list, err := lister.List()
return list.Items, err return list.Items, err
}, },
@ -496,12 +497,12 @@ func TestStoreToJobLister(t *testing.T) {
}, },
// Listing multiple jobs // Listing multiple jobs
{ {
inJobs: []*extensions.Job{ inJobs: []*batch.Job{
{ObjectMeta: api.ObjectMeta{Name: "basic"}}, {ObjectMeta: api.ObjectMeta{Name: "basic"}},
{ObjectMeta: api.ObjectMeta{Name: "complex"}}, {ObjectMeta: api.ObjectMeta{Name: "complex"}},
{ObjectMeta: api.ObjectMeta{Name: "complex2"}}, {ObjectMeta: api.ObjectMeta{Name: "complex2"}},
}, },
list: func() ([]extensions.Job, error) { list: func() ([]batch.Job, error) {
list, err := lister.List() list, err := lister.List()
return list.Items, err return list.Items, err
}, },
@ -510,17 +511,17 @@ func TestStoreToJobLister(t *testing.T) {
}, },
// No pod labels // No pod labels
{ {
inJobs: []*extensions.Job{ inJobs: []*batch.Job{
{ {
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"}, ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "baz"}, MatchLabels: map[string]string{"foo": "baz"},
}, },
}, },
}, },
}, },
list: func() ([]extensions.Job, error) { list: func() ([]batch.Job, error) {
pod := &api.Pod{ pod := &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "pod", Namespace: "ns"}, ObjectMeta: api.ObjectMeta{Name: "pod", Namespace: "ns"},
} }
@ -532,12 +533,12 @@ func TestStoreToJobLister(t *testing.T) {
}, },
// No Job selectors // No Job selectors
{ {
inJobs: []*extensions.Job{ inJobs: []*batch.Job{
{ {
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"}, ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
}, },
}, },
list: func() ([]extensions.Job, error) { list: func() ([]batch.Job, error) {
pod := &api.Pod{ pod := &api.Pod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "pod", Name: "pod",
@ -553,10 +554,10 @@ func TestStoreToJobLister(t *testing.T) {
}, },
// Matching labels to selectors and namespace // Matching labels to selectors and namespace
{ {
inJobs: []*extensions.Job{ inJobs: []*batch.Job{
{ {
ObjectMeta: api.ObjectMeta{Name: "foo"}, ObjectMeta: api.ObjectMeta{Name: "foo"},
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"}, MatchLabels: map[string]string{"foo": "bar"},
}, },
@ -564,14 +565,14 @@ func TestStoreToJobLister(t *testing.T) {
}, },
{ {
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"}, ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"},
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"}, MatchLabels: map[string]string{"foo": "bar"},
}, },
}, },
}, },
}, },
list: func() ([]extensions.Job, error) { list: func() ([]batch.Job, error) {
pod := &api.Pod{ pod := &api.Pod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "pod", Name: "pod",
@ -586,10 +587,10 @@ func TestStoreToJobLister(t *testing.T) {
}, },
// Matching labels to selectors and namespace, error case // Matching labels to selectors and namespace, error case
{ {
inJobs: []*extensions.Job{ inJobs: []*batch.Job{
{ {
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "foo"}, ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "foo"},
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"}, MatchLabels: map[string]string{"foo": "bar"},
}, },
@ -597,14 +598,14 @@ func TestStoreToJobLister(t *testing.T) {
}, },
{ {
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "bar"}, ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "bar"},
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"}, MatchLabels: map[string]string{"foo": "bar"},
}, },
}, },
}, },
}, },
list: func() ([]extensions.Job, error) { list: func() ([]batch.Job, error) {
pod := &api.Pod{ pod := &api.Pod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "pod", Name: "pod",

View File

@ -23,6 +23,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/pkg/watch" "k8s.io/kubernetes/pkg/watch"
@ -129,7 +130,7 @@ func ReplicaSetHasDesiredReplicas(c ExtensionsInterface, replicaSet *extensions.
// JobHasDesiredParallelism returns a condition that will be true if the desired parallelism count // JobHasDesiredParallelism returns a condition that will be true if the desired parallelism count
// for a job equals the current active counts or is less by an appropriate successful/unsuccessful count. // for a job equals the current active counts or is less by an appropriate successful/unsuccessful count.
func JobHasDesiredParallelism(c ExtensionsInterface, job *extensions.Job) wait.ConditionFunc { func JobHasDesiredParallelism(c BatchInterface, job *batch.Job) wait.ConditionFunc {
return func() (bool, error) { return func() (bool, error) {
job, err := c.Jobs(job.Namespace).Get(job.Name) job, err := c.Jobs(job.Namespace).Get(job.Name)

View File

@ -18,7 +18,7 @@ package unversioned
import ( import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/watch" "k8s.io/kubernetes/pkg/watch"
) )
@ -29,13 +29,13 @@ type JobsNamespacer interface {
// JobInterface exposes methods to work on Job resources. // JobInterface exposes methods to work on Job resources.
type JobInterface interface { type JobInterface interface {
List(opts api.ListOptions) (*extensions.JobList, error) List(opts api.ListOptions) (*batch.JobList, error)
Get(name string) (*extensions.Job, error) Get(name string) (*batch.Job, error)
Create(job *extensions.Job) (*extensions.Job, error) Create(job *batch.Job) (*batch.Job, error)
Update(job *extensions.Job) (*extensions.Job, error) Update(job *batch.Job) (*batch.Job, error)
Delete(name string, options *api.DeleteOptions) error Delete(name string, options *api.DeleteOptions) error
Watch(opts api.ListOptions) (watch.Interface, error) Watch(opts api.ListOptions) (watch.Interface, error)
UpdateStatus(job *extensions.Job) (*extensions.Job, error) UpdateStatus(job *batch.Job) (*batch.Job, error)
} }
// jobs implements JobsNamespacer interface // jobs implements JobsNamespacer interface
@ -53,29 +53,29 @@ func newJobs(c *ExtensionsClient, namespace string) *jobs {
var _ JobInterface = &jobs{} var _ JobInterface = &jobs{}
// List returns a list of jobs that match the label and field selectors. // List returns a list of jobs that match the label and field selectors.
func (c *jobs) List(opts api.ListOptions) (result *extensions.JobList, err error) { func (c *jobs) List(opts api.ListOptions) (result *batch.JobList, err error) {
result = &extensions.JobList{} result = &batch.JobList{}
err = c.r.Get().Namespace(c.ns).Resource("jobs").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) err = c.r.Get().Namespace(c.ns).Resource("jobs").VersionedParams(&opts, api.ParameterCodec).Do().Into(result)
return return
} }
// Get returns information about a particular job. // Get returns information about a particular job.
func (c *jobs) Get(name string) (result *extensions.Job, err error) { func (c *jobs) Get(name string) (result *batch.Job, err error) {
result = &extensions.Job{} result = &batch.Job{}
err = c.r.Get().Namespace(c.ns).Resource("jobs").Name(name).Do().Into(result) err = c.r.Get().Namespace(c.ns).Resource("jobs").Name(name).Do().Into(result)
return return
} }
// Create creates a new job. // Create creates a new job.
func (c *jobs) Create(job *extensions.Job) (result *extensions.Job, err error) { func (c *jobs) Create(job *batch.Job) (result *batch.Job, err error) {
result = &extensions.Job{} result = &batch.Job{}
err = c.r.Post().Namespace(c.ns).Resource("jobs").Body(job).Do().Into(result) err = c.r.Post().Namespace(c.ns).Resource("jobs").Body(job).Do().Into(result)
return return
} }
// Update updates an existing job. // Update updates an existing job.
func (c *jobs) Update(job *extensions.Job) (result *extensions.Job, err error) { func (c *jobs) Update(job *batch.Job) (result *batch.Job, err error) {
result = &extensions.Job{} result = &batch.Job{}
err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).Body(job).Do().Into(result) err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).Body(job).Do().Into(result)
return return
} }
@ -96,8 +96,8 @@ func (c *jobs) Watch(opts api.ListOptions) (watch.Interface, error) {
} }
// UpdateStatus takes the name of the job and the new status. Returns the server's representation of the job, and an error, if it occurs. // UpdateStatus takes the name of the job and the new status. Returns the server's representation of the job, and an error, if it occurs.
func (c *jobs) UpdateStatus(job *extensions.Job) (result *extensions.Job, err error) { func (c *jobs) UpdateStatus(job *batch.Job) (result *batch.Job, err error) {
result = &extensions.Job{} result = &batch.Job{}
err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result) err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result)
return return
} }
@ -117,29 +117,29 @@ func newJobsV1(c *BatchClient, namespace string) *jobsV1 {
var _ JobInterface = &jobsV1{} var _ JobInterface = &jobsV1{}
// List returns a list of jobs that match the label and field selectors. // List returns a list of jobs that match the label and field selectors.
func (c *jobsV1) List(opts api.ListOptions) (result *extensions.JobList, err error) { func (c *jobsV1) List(opts api.ListOptions) (result *batch.JobList, err error) {
result = &extensions.JobList{} result = &batch.JobList{}
err = c.r.Get().Namespace(c.ns).Resource("jobs").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) err = c.r.Get().Namespace(c.ns).Resource("jobs").VersionedParams(&opts, api.ParameterCodec).Do().Into(result)
return return
} }
// Get returns information about a particular job. // Get returns information about a particular job.
func (c *jobsV1) Get(name string) (result *extensions.Job, err error) { func (c *jobsV1) Get(name string) (result *batch.Job, err error) {
result = &extensions.Job{} result = &batch.Job{}
err = c.r.Get().Namespace(c.ns).Resource("jobs").Name(name).Do().Into(result) err = c.r.Get().Namespace(c.ns).Resource("jobs").Name(name).Do().Into(result)
return return
} }
// Create creates a new job. // Create creates a new job.
func (c *jobsV1) Create(job *extensions.Job) (result *extensions.Job, err error) { func (c *jobsV1) Create(job *batch.Job) (result *batch.Job, err error) {
result = &extensions.Job{} result = &batch.Job{}
err = c.r.Post().Namespace(c.ns).Resource("jobs").Body(job).Do().Into(result) err = c.r.Post().Namespace(c.ns).Resource("jobs").Body(job).Do().Into(result)
return return
} }
// Update updates an existing job. // Update updates an existing job.
func (c *jobsV1) Update(job *extensions.Job) (result *extensions.Job, err error) { func (c *jobsV1) Update(job *batch.Job) (result *batch.Job, err error) {
result = &extensions.Job{} result = &batch.Job{}
err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).Body(job).Do().Into(result) err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).Body(job).Do().Into(result)
return return
} }
@ -160,8 +160,8 @@ func (c *jobsV1) Watch(opts api.ListOptions) (watch.Interface, error) {
} }
// UpdateStatus takes the name of the job and the new status. Returns the server's representation of the job, and an error, if it occurs. // UpdateStatus takes the name of the job and the new status. Returns the server's representation of the job, and an error, if it occurs.
func (c *jobsV1) UpdateStatus(job *extensions.Job) (result *extensions.Job, err error) { func (c *jobsV1) UpdateStatus(job *batch.Job) (result *batch.Job, err error) {
result = &extensions.Job{} result = &batch.Job{}
err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result) err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result)
return return
} }

View File

@ -51,8 +51,8 @@ func testListJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
Path: group.ResourcePath(getJobsResourceName(), ns, ""), Path: group.ResourcePath(getJobsResourceName(), ns, ""),
}, },
Response: simple.Response{StatusCode: 200, Response: simple.Response{StatusCode: 200,
Body: &extensions.JobList{ Body: &batch.JobList{
Items: []extensions.Job{ Items: []batch.Job{
{ {
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
@ -61,7 +61,7 @@ func testListJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
"name": "baz", "name": "baz",
}, },
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Template: api.PodTemplateSpec{}, Template: api.PodTemplateSpec{},
}, },
}, },
@ -90,7 +90,7 @@ func testGetJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
}, },
Response: simple.Response{ Response: simple.Response{
StatusCode: 200, StatusCode: 200,
Body: &extensions.Job{ Body: &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{ Labels: map[string]string{
@ -98,7 +98,7 @@ func testGetJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
"name": "baz", "name": "baz",
}, },
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Template: api.PodTemplateSpec{}, Template: api.PodTemplateSpec{},
}, },
}, },
@ -117,7 +117,7 @@ func TestGetJob(t *testing.T) {
func testUpdateJob(t *testing.T, group testapi.TestGroup, resourceGroup string) { func testUpdateJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault ns := api.NamespaceDefault
requestJob := &extensions.Job{ requestJob := &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
Namespace: ns, Namespace: ns,
@ -132,7 +132,7 @@ func testUpdateJob(t *testing.T, group testapi.TestGroup, resourceGroup string)
}, },
Response: simple.Response{ Response: simple.Response{
StatusCode: 200, StatusCode: 200,
Body: &extensions.Job{ Body: &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{ Labels: map[string]string{
@ -140,7 +140,7 @@ func testUpdateJob(t *testing.T, group testapi.TestGroup, resourceGroup string)
"name": "baz", "name": "baz",
}, },
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Template: api.PodTemplateSpec{}, Template: api.PodTemplateSpec{},
}, },
}, },
@ -159,7 +159,7 @@ func TestUpdateJob(t *testing.T) {
func testUpdateJobStatus(t *testing.T, group testapi.TestGroup, resourceGroup string) { func testUpdateJobStatus(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault ns := api.NamespaceDefault
requestJob := &extensions.Job{ requestJob := &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
Namespace: ns, Namespace: ns,
@ -174,7 +174,7 @@ func testUpdateJobStatus(t *testing.T, group testapi.TestGroup, resourceGroup st
}, },
Response: simple.Response{ Response: simple.Response{
StatusCode: 200, StatusCode: 200,
Body: &extensions.Job{ Body: &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{ Labels: map[string]string{
@ -182,10 +182,10 @@ func testUpdateJobStatus(t *testing.T, group testapi.TestGroup, resourceGroup st
"name": "baz", "name": "baz",
}, },
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Template: api.PodTemplateSpec{}, Template: api.PodTemplateSpec{},
}, },
Status: extensions.JobStatus{ Status: batch.JobStatus{
Active: 1, Active: 1,
}, },
}, },
@ -225,7 +225,7 @@ func TestDeleteJob(t *testing.T) {
func testCreateJob(t *testing.T, group testapi.TestGroup, resourceGroup string) { func testCreateJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault ns := api.NamespaceDefault
requestJob := &extensions.Job{ requestJob := &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
Namespace: ns, Namespace: ns,
@ -240,7 +240,7 @@ func testCreateJob(t *testing.T, group testapi.TestGroup, resourceGroup string)
}, },
Response: simple.Response{ Response: simple.Response{
StatusCode: 200, StatusCode: 200,
Body: &extensions.Job{ Body: &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{ Labels: map[string]string{
@ -248,7 +248,7 @@ func testCreateJob(t *testing.T, group testapi.TestGroup, resourceGroup string)
"name": "baz", "name": "baz",
}, },
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Template: api.PodTemplateSpec{}, Template: api.PodTemplateSpec{},
}, },
}, },

View File

@ -18,7 +18,7 @@ package testclient
import ( import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/watch" "k8s.io/kubernetes/pkg/watch"
) )
@ -29,44 +29,44 @@ type FakeJobs struct {
Namespace string Namespace string
} }
func (c *FakeJobs) Get(name string) (*extensions.Job, error) { func (c *FakeJobs) Get(name string) (*batch.Job, error) {
obj, err := c.Fake.Invokes(NewGetAction("jobs", c.Namespace, name), &extensions.Job{}) obj, err := c.Fake.Invokes(NewGetAction("jobs", c.Namespace, name), &batch.Job{})
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*extensions.Job), err return obj.(*batch.Job), err
} }
func (c *FakeJobs) List(opts api.ListOptions) (*extensions.JobList, error) { func (c *FakeJobs) List(opts api.ListOptions) (*batch.JobList, error) {
obj, err := c.Fake.Invokes(NewListAction("jobs", c.Namespace, opts), &extensions.JobList{}) obj, err := c.Fake.Invokes(NewListAction("jobs", c.Namespace, opts), &batch.JobList{})
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*extensions.JobList), err return obj.(*batch.JobList), err
} }
func (c *FakeJobs) Create(job *extensions.Job) (*extensions.Job, error) { func (c *FakeJobs) Create(job *batch.Job) (*batch.Job, error) {
obj, err := c.Fake.Invokes(NewCreateAction("jobs", c.Namespace, job), job) obj, err := c.Fake.Invokes(NewCreateAction("jobs", c.Namespace, job), job)
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*extensions.Job), err return obj.(*batch.Job), err
} }
func (c *FakeJobs) Update(job *extensions.Job) (*extensions.Job, error) { func (c *FakeJobs) Update(job *batch.Job) (*batch.Job, error) {
obj, err := c.Fake.Invokes(NewUpdateAction("jobs", c.Namespace, job), job) obj, err := c.Fake.Invokes(NewUpdateAction("jobs", c.Namespace, job), job)
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*extensions.Job), err return obj.(*batch.Job), err
} }
func (c *FakeJobs) Delete(name string, options *api.DeleteOptions) error { func (c *FakeJobs) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.Invokes(NewDeleteAction("jobs", c.Namespace, name), &extensions.Job{}) _, err := c.Fake.Invokes(NewDeleteAction("jobs", c.Namespace, name), &batch.Job{})
return err return err
} }
@ -74,13 +74,13 @@ func (c *FakeJobs) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.InvokesWatch(NewWatchAction("jobs", c.Namespace, opts)) return c.Fake.InvokesWatch(NewWatchAction("jobs", c.Namespace, opts))
} }
func (c *FakeJobs) UpdateStatus(job *extensions.Job) (result *extensions.Job, err error) { func (c *FakeJobs) UpdateStatus(job *batch.Job) (result *batch.Job, err error) {
obj, err := c.Fake.Invokes(NewUpdateSubresourceAction("jobs", "status", c.Namespace, job), job) obj, err := c.Fake.Invokes(NewUpdateSubresourceAction("jobs", "status", c.Namespace, job), job)
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*extensions.Job), err return obj.(*batch.Job), err
} }
// FakeJobs implements JobInterface. Meant to be embedded into a struct to get a default // FakeJobs implements JobInterface. Meant to be embedded into a struct to get a default
@ -92,44 +92,44 @@ type FakeJobsV1 struct {
Namespace string Namespace string
} }
func (c *FakeJobsV1) Get(name string) (*extensions.Job, error) { func (c *FakeJobsV1) Get(name string) (*batch.Job, error) {
obj, err := c.Fake.Invokes(NewGetAction("jobs", c.Namespace, name), &extensions.Job{}) obj, err := c.Fake.Invokes(NewGetAction("jobs", c.Namespace, name), &batch.Job{})
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*extensions.Job), err return obj.(*batch.Job), err
} }
func (c *FakeJobsV1) List(opts api.ListOptions) (*extensions.JobList, error) { func (c *FakeJobsV1) List(opts api.ListOptions) (*batch.JobList, error) {
obj, err := c.Fake.Invokes(NewListAction("jobs", c.Namespace, opts), &extensions.JobList{}) obj, err := c.Fake.Invokes(NewListAction("jobs", c.Namespace, opts), &batch.JobList{})
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*extensions.JobList), err return obj.(*batch.JobList), err
} }
func (c *FakeJobsV1) Create(job *extensions.Job) (*extensions.Job, error) { func (c *FakeJobsV1) Create(job *batch.Job) (*batch.Job, error) {
obj, err := c.Fake.Invokes(NewCreateAction("jobs", c.Namespace, job), job) obj, err := c.Fake.Invokes(NewCreateAction("jobs", c.Namespace, job), job)
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*extensions.Job), err return obj.(*batch.Job), err
} }
func (c *FakeJobsV1) Update(job *extensions.Job) (*extensions.Job, error) { func (c *FakeJobsV1) Update(job *batch.Job) (*batch.Job, error) {
obj, err := c.Fake.Invokes(NewUpdateAction("jobs", c.Namespace, job), job) obj, err := c.Fake.Invokes(NewUpdateAction("jobs", c.Namespace, job), job)
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*extensions.Job), err return obj.(*batch.Job), err
} }
func (c *FakeJobsV1) Delete(name string, options *api.DeleteOptions) error { func (c *FakeJobsV1) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.Invokes(NewDeleteAction("jobs", c.Namespace, name), &extensions.Job{}) _, err := c.Fake.Invokes(NewDeleteAction("jobs", c.Namespace, name), &batch.Job{})
return err return err
} }
@ -137,11 +137,11 @@ func (c *FakeJobsV1) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.InvokesWatch(NewWatchAction("jobs", c.Namespace, opts)) return c.Fake.InvokesWatch(NewWatchAction("jobs", c.Namespace, opts))
} }
func (c *FakeJobsV1) UpdateStatus(job *extensions.Job) (result *extensions.Job, err error) { func (c *FakeJobsV1) UpdateStatus(job *batch.Job) (result *batch.Job, err error) {
obj, err := c.Fake.Invokes(NewUpdateSubresourceAction("jobs", "status", c.Namespace, job), job) obj, err := c.Fake.Invokes(NewUpdateSubresourceAction("jobs", "status", c.Namespace, job), job)
if obj == nil { if obj == nil {
return nil, err return nil, err
} }
return obj.(*extensions.Job), err return obj.(*batch.Job), err
} }

View File

@ -25,7 +25,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/client/cache" "k8s.io/kubernetes/pkg/client/cache"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
unversionedcore "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/unversioned" unversionedcore "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/unversioned"
@ -53,7 +53,7 @@ type JobController struct {
internalPodInformer framework.SharedInformer internalPodInformer framework.SharedInformer
// To allow injection of updateJobStatus for testing. // To allow injection of updateJobStatus for testing.
updateHandler func(job *extensions.Job) error updateHandler func(job *batch.Job) error
syncHandler func(jobKey string) error syncHandler func(jobKey string) error
// podStoreSynced returns true if the pod store has been synced at least once. // podStoreSynced returns true if the pod store has been synced at least once.
// Added as a member to the struct to allow injection for testing. // Added as a member to the struct to allow injection for testing.
@ -96,19 +96,19 @@ func NewJobController(podInformer framework.SharedInformer, kubeClient clientset
jm.jobStore.Store, jm.jobController = framework.NewInformer( jm.jobStore.Store, jm.jobController = framework.NewInformer(
&cache.ListWatch{ &cache.ListWatch{
ListFunc: func(options api.ListOptions) (runtime.Object, error) { ListFunc: func(options api.ListOptions) (runtime.Object, error) {
return jm.kubeClient.Extensions().Jobs(api.NamespaceAll).List(options) return jm.kubeClient.Batch().Jobs(api.NamespaceAll).List(options)
}, },
WatchFunc: func(options api.ListOptions) (watch.Interface, error) { WatchFunc: func(options api.ListOptions) (watch.Interface, error) {
return jm.kubeClient.Extensions().Jobs(api.NamespaceAll).Watch(options) return jm.kubeClient.Batch().Jobs(api.NamespaceAll).Watch(options)
}, },
}, },
&extensions.Job{}, &batch.Job{},
// TODO: Can we have much longer period here? // TODO: Can we have much longer period here?
replicationcontroller.FullControllerResyncPeriod, replicationcontroller.FullControllerResyncPeriod,
framework.ResourceEventHandlerFuncs{ framework.ResourceEventHandlerFuncs{
AddFunc: jm.enqueueController, AddFunc: jm.enqueueController,
UpdateFunc: func(old, cur interface{}) { UpdateFunc: func(old, cur interface{}) {
if job := cur.(*extensions.Job); !isJobFinished(job) { if job := cur.(*batch.Job); !isJobFinished(job) {
jm.enqueueController(job) jm.enqueueController(job)
} }
}, },
@ -155,7 +155,7 @@ func (jm *JobController) Run(workers int, stopCh <-chan struct{}) {
} }
// getPodJob returns the job managing the given pod. // getPodJob returns the job managing the given pod.
func (jm *JobController) getPodJob(pod *api.Pod) *extensions.Job { func (jm *JobController) getPodJob(pod *api.Pod) *batch.Job {
jobs, err := jm.jobStore.GetPodJobs(pod) jobs, err := jm.jobStore.GetPodJobs(pod)
if err != nil { if err != nil {
glog.V(4).Infof("No jobs found for pod %v, job controller will avoid syncing", pod.Name) glog.V(4).Infof("No jobs found for pod %v, job controller will avoid syncing", pod.Name)
@ -251,7 +251,7 @@ func (jm *JobController) deletePod(obj interface{}) {
} }
} }
// obj could be an *extensions.Job, or a DeletionFinalStateUnknown marker item. // obj could be an *batch.Job, or a DeletionFinalStateUnknown marker item.
func (jm *JobController) enqueueController(obj interface{}) { func (jm *JobController) enqueueController(obj interface{}) {
key, err := controller.KeyFunc(obj) key, err := controller.KeyFunc(obj)
if err != nil { if err != nil {
@ -314,7 +314,7 @@ func (jm *JobController) syncJob(key string) error {
jm.queue.Add(key) jm.queue.Add(key)
return err return err
} }
job := *obj.(*extensions.Job) job := *obj.(*batch.Job)
// Check the expectations of the job before counting active pods, otherwise a new pod can sneak in // Check the expectations of the job before counting active pods, otherwise a new pod can sneak in
// and update the expectations after we've retrieved active pods from the store. If a new pod enters // and update the expectations after we've retrieved active pods from the store. If a new pod enters
@ -366,7 +366,7 @@ func (jm *JobController) syncJob(key string) error {
// update status values accordingly // update status values accordingly
failed += active failed += active
active = 0 active = 0
job.Status.Conditions = append(job.Status.Conditions, newCondition(extensions.JobFailed, "DeadlineExceeded", "Job was active longer than specified deadline")) job.Status.Conditions = append(job.Status.Conditions, newCondition(batch.JobFailed, "DeadlineExceeded", "Job was active longer than specified deadline"))
jm.recorder.Event(&job, api.EventTypeNormal, "DeadlineExceeded", "Job was active longer than specified deadline") jm.recorder.Event(&job, api.EventTypeNormal, "DeadlineExceeded", "Job was active longer than specified deadline")
} else { } else {
if jobNeedsSync { if jobNeedsSync {
@ -400,7 +400,7 @@ func (jm *JobController) syncJob(key string) error {
} }
} }
if complete { if complete {
job.Status.Conditions = append(job.Status.Conditions, newCondition(extensions.JobComplete, "", "")) job.Status.Conditions = append(job.Status.Conditions, newCondition(batch.JobComplete, "", ""))
now := unversioned.Now() now := unversioned.Now()
job.Status.CompletionTime = &now job.Status.CompletionTime = &now
} }
@ -421,7 +421,7 @@ func (jm *JobController) syncJob(key string) error {
} }
// pastActiveDeadline checks if job has ActiveDeadlineSeconds field set and if it is exceeded. // pastActiveDeadline checks if job has ActiveDeadlineSeconds field set and if it is exceeded.
func pastActiveDeadline(job *extensions.Job) bool { func pastActiveDeadline(job *batch.Job) bool {
if job.Spec.ActiveDeadlineSeconds == nil || job.Status.StartTime == nil { if job.Spec.ActiveDeadlineSeconds == nil || job.Status.StartTime == nil {
return false return false
} }
@ -432,8 +432,8 @@ func pastActiveDeadline(job *extensions.Job) bool {
return duration >= allowedDuration return duration >= allowedDuration
} }
func newCondition(conditionType extensions.JobConditionType, reason, message string) extensions.JobCondition { func newCondition(conditionType batch.JobConditionType, reason, message string) batch.JobCondition {
return extensions.JobCondition{ return batch.JobCondition{
Type: conditionType, Type: conditionType,
Status: api.ConditionTrue, Status: api.ConditionTrue,
LastProbeTime: unversioned.Now(), LastProbeTime: unversioned.Now(),
@ -452,7 +452,7 @@ func getStatus(pods []api.Pod) (succeeded, failed int) {
// manageJob is the core method responsible for managing the number of running // manageJob is the core method responsible for managing the number of running
// pods according to what is specified in the job.Spec. // pods according to what is specified in the job.Spec.
func (jm *JobController) manageJob(activePods []*api.Pod, succeeded int, job *extensions.Job) int { func (jm *JobController) manageJob(activePods []*api.Pod, succeeded int, job *batch.Job) int {
var activeLock sync.Mutex var activeLock sync.Mutex
active := len(activePods) active := len(activePods)
parallelism := *job.Spec.Parallelism parallelism := *job.Spec.Parallelism
@ -538,8 +538,8 @@ func (jm *JobController) manageJob(activePods []*api.Pod, succeeded int, job *ex
return active return active
} }
func (jm *JobController) updateJobStatus(job *extensions.Job) error { func (jm *JobController) updateJobStatus(job *batch.Job) error {
_, err := jm.kubeClient.Extensions().Jobs(job.Namespace).UpdateStatus(job) _, err := jm.kubeClient.Batch().Jobs(job.Namespace).UpdateStatus(job)
return err return err
} }
@ -554,9 +554,9 @@ func filterPods(pods []api.Pod, phase api.PodPhase) int {
return result return result
} }
func isJobFinished(j *extensions.Job) bool { func isJobFinished(j *batch.Job) bool {
for _, c := range j.Status.Conditions { for _, c := range j.Status.Conditions {
if (c.Type == extensions.JobComplete || c.Type == extensions.JobFailed) && c.Status == api.ConditionTrue { if (c.Type == batch.JobComplete || c.Type == batch.JobFailed) && c.Status == api.ConditionTrue {
return true return true
} }
} }
@ -564,7 +564,7 @@ func isJobFinished(j *extensions.Job) bool {
} }
// byCreationTimestamp sorts a list by creation timestamp, using their names as a tie breaker. // byCreationTimestamp sorts a list by creation timestamp, using their names as a tie breaker.
type byCreationTimestamp []extensions.Job type byCreationTimestamp []batch.Job
func (o byCreationTimestamp) Len() int { return len(o) } func (o byCreationTimestamp) Len() int { return len(o) }
func (o byCreationTimestamp) Swap(i, j int) { o[i], o[j] = o[j], o[i] } func (o byCreationTimestamp) Swap(i, j int) { o[i], o[j] = o[j], o[i] }

View File

@ -24,7 +24,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/batch"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/restclient"
@ -37,13 +37,13 @@ import (
var alwaysReady = func() bool { return true } var alwaysReady = func() bool { return true }
func newJob(parallelism, completions int) *extensions.Job { func newJob(parallelism, completions int) *batch.Job {
j := &extensions.Job{ j := &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foobar", Name: "foobar",
Namespace: api.NamespaceDefault, Namespace: api.NamespaceDefault,
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"}, MatchLabels: map[string]string{"foo": "bar"},
}, },
@ -76,7 +76,7 @@ func newJob(parallelism, completions int) *extensions.Job {
return j return j
} }
func getKey(job *extensions.Job, t *testing.T) string { func getKey(job *batch.Job, t *testing.T) string {
if key, err := controller.KeyFunc(job); err != nil { if key, err := controller.KeyFunc(job); err != nil {
t.Errorf("Unexpected error getting key for job %v: %v", job.Name, err) t.Errorf("Unexpected error getting key for job %v: %v", job.Name, err)
return "" return ""
@ -86,7 +86,7 @@ func getKey(job *extensions.Job, t *testing.T) string {
} }
// create count pods with the given phase for the given job // create count pods with the given phase for the given job
func newPodList(count int, status api.PodPhase, job *extensions.Job) []api.Pod { func newPodList(count int, status api.PodPhase, job *batch.Job) []api.Pod {
pods := []api.Pod{} pods := []api.Pod{}
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
newPod := api.Pod{ newPod := api.Pod{
@ -211,8 +211,8 @@ func TestControllerSyncJob(t *testing.T) {
fakePodControl := controller.FakePodControl{Err: tc.podControllerError} fakePodControl := controller.FakePodControl{Err: tc.podControllerError}
manager.podControl = &fakePodControl manager.podControl = &fakePodControl
manager.podStoreSynced = alwaysReady manager.podStoreSynced = alwaysReady
var actual *extensions.Job var actual *batch.Job
manager.updateHandler = func(job *extensions.Job) error { manager.updateHandler = func(job *batch.Job) error {
actual = job actual = job
return nil return nil
} }
@ -257,7 +257,7 @@ func TestControllerSyncJob(t *testing.T) {
t.Errorf("%s: .status.startTime was not set", name) t.Errorf("%s: .status.startTime was not set", name)
} }
// validate conditions // validate conditions
if tc.expectedComplete && !getCondition(actual, extensions.JobComplete) { if tc.expectedComplete && !getCondition(actual, batch.JobComplete) {
t.Errorf("%s: expected completion condition. Got %#v", name, actual.Status.Conditions) t.Errorf("%s: expected completion condition. Got %#v", name, actual.Status.Conditions)
} }
} }
@ -306,8 +306,8 @@ func TestSyncJobPastDeadline(t *testing.T) {
fakePodControl := controller.FakePodControl{} fakePodControl := controller.FakePodControl{}
manager.podControl = &fakePodControl manager.podControl = &fakePodControl
manager.podStoreSynced = alwaysReady manager.podStoreSynced = alwaysReady
var actual *extensions.Job var actual *batch.Job
manager.updateHandler = func(job *extensions.Job) error { manager.updateHandler = func(job *batch.Job) error {
actual = job actual = job
return nil return nil
} }
@ -355,13 +355,13 @@ func TestSyncJobPastDeadline(t *testing.T) {
t.Errorf("%s: .status.startTime was not set", name) t.Errorf("%s: .status.startTime was not set", name)
} }
// validate conditions // validate conditions
if !getCondition(actual, extensions.JobFailed) { if !getCondition(actual, batch.JobFailed) {
t.Errorf("%s: expected fail condition. Got %#v", name, actual.Status.Conditions) t.Errorf("%s: expected fail condition. Got %#v", name, actual.Status.Conditions)
} }
} }
} }
func getCondition(job *extensions.Job, condition extensions.JobConditionType) bool { func getCondition(job *batch.Job, condition batch.JobConditionType) bool {
for _, v := range job.Status.Conditions { for _, v := range job.Status.Conditions {
if v.Type == condition && v.Status == api.ConditionTrue { if v.Type == condition && v.Status == api.ConditionTrue {
return true return true
@ -376,8 +376,8 @@ func TestSyncPastDeadlineJobFinished(t *testing.T) {
fakePodControl := controller.FakePodControl{} fakePodControl := controller.FakePodControl{}
manager.podControl = &fakePodControl manager.podControl = &fakePodControl
manager.podStoreSynced = alwaysReady manager.podStoreSynced = alwaysReady
var actual *extensions.Job var actual *batch.Job
manager.updateHandler = func(job *extensions.Job) error { manager.updateHandler = func(job *batch.Job) error {
actual = job actual = job
return nil return nil
} }
@ -387,7 +387,7 @@ func TestSyncPastDeadlineJobFinished(t *testing.T) {
job.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds job.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds
start := unversioned.Unix(unversioned.Now().Time.Unix()-15, 0) start := unversioned.Unix(unversioned.Now().Time.Unix()-15, 0)
job.Status.StartTime = &start job.Status.StartTime = &start
job.Status.Conditions = append(job.Status.Conditions, newCondition(extensions.JobFailed, "DeadlineExceeded", "Job was active longer than specified deadline")) job.Status.Conditions = append(job.Status.Conditions, newCondition(batch.JobFailed, "DeadlineExceeded", "Job was active longer than specified deadline"))
manager.jobStore.Store.Add(job) manager.jobStore.Store.Add(job)
err := manager.syncJob(getKey(job, t)) err := manager.syncJob(getKey(job, t))
if err != nil { if err != nil {
@ -412,7 +412,7 @@ func TestSyncJobComplete(t *testing.T) {
manager.podStoreSynced = alwaysReady manager.podStoreSynced = alwaysReady
job := newJob(1, 1) job := newJob(1, 1)
job.Status.Conditions = append(job.Status.Conditions, newCondition(extensions.JobComplete, "", "")) job.Status.Conditions = append(job.Status.Conditions, newCondition(batch.JobComplete, "", ""))
manager.jobStore.Store.Add(job) manager.jobStore.Store.Add(job)
err := manager.syncJob(getKey(job, t)) err := manager.syncJob(getKey(job, t))
if err != nil { if err != nil {
@ -422,7 +422,7 @@ func TestSyncJobComplete(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Unexpected error when trying to get job from the store: %v", err) t.Fatalf("Unexpected error when trying to get job from the store: %v", err)
} }
actual := uncastJob.(*extensions.Job) actual := uncastJob.(*batch.Job)
// Verify that after syncing a complete job, the conditions are the same. // Verify that after syncing a complete job, the conditions are the same.
if got, expected := len(actual.Status.Conditions), 1; got != expected { if got, expected := len(actual.Status.Conditions), 1; got != expected {
t.Fatalf("Unexpected job status conditions amount; expected %d, got %d", expected, got) t.Fatalf("Unexpected job status conditions amount; expected %d, got %d", expected, got)
@ -435,7 +435,7 @@ func TestSyncJobDeleted(t *testing.T) {
fakePodControl := controller.FakePodControl{} fakePodControl := controller.FakePodControl{}
manager.podControl = &fakePodControl manager.podControl = &fakePodControl
manager.podStoreSynced = alwaysReady manager.podStoreSynced = alwaysReady
manager.updateHandler = func(job *extensions.Job) error { return nil } manager.updateHandler = func(job *batch.Job) error { return nil }
job := newJob(2, 2) job := newJob(2, 2)
err := manager.syncJob(getKey(job, t)) err := manager.syncJob(getKey(job, t))
if err != nil { if err != nil {
@ -455,7 +455,7 @@ func TestSyncJobUpdateRequeue(t *testing.T) {
fakePodControl := controller.FakePodControl{} fakePodControl := controller.FakePodControl{}
manager.podControl = &fakePodControl manager.podControl = &fakePodControl
manager.podStoreSynced = alwaysReady manager.podStoreSynced = alwaysReady
manager.updateHandler = func(job *extensions.Job) error { return fmt.Errorf("Fake error") } manager.updateHandler = func(job *batch.Job) error { return fmt.Errorf("Fake error") }
job := newJob(2, 2) job := newJob(2, 2)
manager.jobStore.Store.Add(job) manager.jobStore.Store.Add(job)
err := manager.syncJob(getKey(job, t)) err := manager.syncJob(getKey(job, t))
@ -475,14 +475,14 @@ func TestJobPodLookup(t *testing.T) {
manager := NewJobControllerFromClient(clientset, controller.NoResyncPeriodFunc) manager := NewJobControllerFromClient(clientset, controller.NoResyncPeriodFunc)
manager.podStoreSynced = alwaysReady manager.podStoreSynced = alwaysReady
testCases := []struct { testCases := []struct {
job *extensions.Job job *batch.Job
pod *api.Pod pod *api.Pod
expectedName string expectedName string
}{ }{
// pods without labels don't match any job // pods without labels don't match any job
{ {
job: &extensions.Job{ job: &batch.Job{
ObjectMeta: api.ObjectMeta{Name: "basic"}, ObjectMeta: api.ObjectMeta{Name: "basic"},
}, },
pod: &api.Pod{ pod: &api.Pod{
@ -492,9 +492,9 @@ func TestJobPodLookup(t *testing.T) {
}, },
// matching labels, different namespace // matching labels, different namespace
{ {
job: &extensions.Job{ job: &batch.Job{
ObjectMeta: api.ObjectMeta{Name: "foo"}, ObjectMeta: api.ObjectMeta{Name: "foo"},
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"}, MatchLabels: map[string]string{"foo": "bar"},
}, },
@ -511,9 +511,9 @@ func TestJobPodLookup(t *testing.T) {
}, },
// matching ns and labels returns // matching ns and labels returns
{ {
job: &extensions.Job{ job: &batch.Job{
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"}, ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"},
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchExpressions: []unversioned.LabelSelectorRequirement{ MatchExpressions: []unversioned.LabelSelectorRequirement{
{ {
@ -566,7 +566,7 @@ func TestSyncJobExpectations(t *testing.T) {
fakePodControl := controller.FakePodControl{} fakePodControl := controller.FakePodControl{}
manager.podControl = &fakePodControl manager.podControl = &fakePodControl
manager.podStoreSynced = alwaysReady manager.podStoreSynced = alwaysReady
manager.updateHandler = func(job *extensions.Job) error { return nil } manager.updateHandler = func(job *batch.Job) error { return nil }
job := newJob(2, 2) job := newJob(2, 2)
manager.jobStore.Store.Add(job) manager.jobStore.Store.Add(job)
@ -602,7 +602,7 @@ func TestWatchJobs(t *testing.T) {
manager := NewJobControllerFromClient(clientset, controller.NoResyncPeriodFunc) manager := NewJobControllerFromClient(clientset, controller.NoResyncPeriodFunc)
manager.podStoreSynced = alwaysReady manager.podStoreSynced = alwaysReady
var testJob extensions.Job var testJob batch.Job
received := make(chan struct{}) received := make(chan struct{})
// The update sent through the fakeWatcher should make its way into the workqueue, // The update sent through the fakeWatcher should make its way into the workqueue,
@ -613,7 +613,7 @@ func TestWatchJobs(t *testing.T) {
if !exists || err != nil { if !exists || err != nil {
t.Errorf("Expected to find job under key %v", key) t.Errorf("Expected to find job under key %v", key)
} }
job, ok := obj.(*extensions.Job) job, ok := obj.(*batch.Job)
if !ok { if !ok {
t.Fatalf("unexpected type: %v %#v", reflect.TypeOf(obj), obj) t.Fatalf("unexpected type: %v %#v", reflect.TypeOf(obj), obj)
} }
@ -637,10 +637,10 @@ func TestWatchJobs(t *testing.T) {
} }
func TestIsJobFinished(t *testing.T) { func TestIsJobFinished(t *testing.T) {
job := &extensions.Job{ job := &batch.Job{
Status: extensions.JobStatus{ Status: batch.JobStatus{
Conditions: []extensions.JobCondition{{ Conditions: []batch.JobCondition{{
Type: extensions.JobComplete, Type: batch.JobComplete,
Status: api.ConditionTrue, Status: api.ConditionTrue,
}}, }},
}, },
@ -681,7 +681,7 @@ func TestWatchPods(t *testing.T) {
close(received) close(received)
return nil return nil
} }
job, ok := obj.(*extensions.Job) job, ok := obj.(*batch.Job)
if !ok { if !ok {
t.Errorf("unexpected type: %v %#v", reflect.TypeOf(obj), obj) t.Errorf("unexpected type: %v %#v", reflect.TypeOf(obj), obj)
close(received) close(received)

View File

@ -33,6 +33,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/unversioned/fake" "k8s.io/kubernetes/pkg/client/unversioned/fake"
@ -262,14 +263,14 @@ func TestDrain(t *testing.T) {
}, },
} }
job := extensions.Job{ job := batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "job", Name: "job",
Namespace: "default", Namespace: "default",
CreationTimestamp: unversioned.Time{Time: time.Now()}, CreationTimestamp: unversioned.Time{Time: time.Now()},
SelfLink: "/apis/extensions/v1beta1/namespaces/default/jobs/job", SelfLink: "/apis/extensions/v1beta1/namespaces/default/jobs/job",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{MatchLabels: labels}, Selector: &unversioned.LabelSelector{MatchLabels: labels},
}, },
} }

View File

@ -665,7 +665,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
} }
pod, _, err := GetFirstPod(client, t.Namespace, selector) pod, _, err := GetFirstPod(client, t.Namespace, selector)
return pod, err return pod, err
case *extensions.Job: case *batch.Job:
selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid label selector: %v", err) return nil, fmt.Errorf("invalid label selector: %v", err)

View File

@ -1089,7 +1089,7 @@ func (d *JobDescriber) Describe(namespace, name string) (string, error) {
return describeJob(job, events) return describeJob(job, events)
} }
func describeJob(job *extensions.Job, events *api.EventList) (string, error) { func describeJob(job *batch.Job, events *api.EventList) (string, error) {
return tabbedString(func(out io.Writer) error { return tabbedString(func(out io.Writer) error {
fmt.Fprintf(out, "Name:\t%s\n", job.Name) fmt.Fprintf(out, "Name:\t%s\n", job.Name)
fmt.Fprintf(out, "Namespace:\t%s\n", job.Namespace) fmt.Fprintf(out, "Namespace:\t%s\n", job.Namespace)

View File

@ -36,6 +36,7 @@ import (
"k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/apps"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
@ -795,7 +796,7 @@ func printReplicaSetList(list *extensions.ReplicaSetList, w io.Writer, options P
return nil return nil
} }
func printJob(job *extensions.Job, w io.Writer, options PrintOptions) error { func printJob(job *batch.Job, w io.Writer, options PrintOptions) error {
name := job.Name name := job.Name
namespace := job.Namespace namespace := job.Namespace
containers := job.Spec.Template.Spec.Containers containers := job.Spec.Template.Spec.Containers
@ -848,7 +849,7 @@ func printJob(job *extensions.Job, w io.Writer, options PrintOptions) error {
return nil return nil
} }
func printJobList(list *extensions.JobList, w io.Writer, options PrintOptions) error { func printJobList(list *batch.JobList, w io.Writer, options PrintOptions) error {
for _, job := range list.Items { for _, job := range list.Items {
if err := printJob(&job, w, options); err != nil { if err := printJob(&job, w, options); err != nil {
return err return err
@ -1784,7 +1785,7 @@ func formatWideHeaders(wide bool, t reflect.Type) []string {
if t.String() == "*api.ReplicationController" || t.String() == "*api.ReplicationControllerList" { if t.String() == "*api.ReplicationController" || t.String() == "*api.ReplicationControllerList" {
return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"} return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
} }
if t.String() == "*extensions.Job" || t.String() == "*extensions.JobList" { if t.String() == "*batch.Job" || t.String() == "*batch.JobList" {
return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"} return []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
} }
if t.String() == "*api.Service" || t.String() == "*api.ServiceList" { if t.String() == "*api.Service" || t.String() == "*api.ServiceList" {

View File

@ -30,6 +30,7 @@ import (
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
kubectltesting "k8s.io/kubernetes/pkg/kubectl/testing" kubectltesting "k8s.io/kubernetes/pkg/kubectl/testing"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
@ -1343,34 +1344,34 @@ func TestPrintDaemonSet(t *testing.T) {
func TestPrintJob(t *testing.T) { func TestPrintJob(t *testing.T) {
completions := 2 completions := 2
tests := []struct { tests := []struct {
job extensions.Job job batch.Job
expect string expect string
}{ }{
{ {
extensions.Job{ batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "job1", Name: "job1",
CreationTimestamp: unversioned.Time{Time: time.Now().Add(1.9e9)}, CreationTimestamp: unversioned.Time{Time: time.Now().Add(1.9e9)},
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Completions: &completions, Completions: &completions,
}, },
Status: extensions.JobStatus{ Status: batch.JobStatus{
Succeeded: 1, Succeeded: 1,
}, },
}, },
"job1\t2\t1\t0s\n", "job1\t2\t1\t0s\n",
}, },
{ {
extensions.Job{ batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "job2", Name: "job2",
CreationTimestamp: unversioned.Time{Time: time.Now().AddDate(-10, 0, 0)}, CreationTimestamp: unversioned.Time{Time: time.Now().AddDate(-10, 0, 0)},
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Completions: nil, Completions: nil,
}, },
Status: extensions.JobStatus{ Status: batch.JobStatus{
Succeeded: 0, Succeeded: 0,
}, },
}, },

View File

@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/batch"
batchv1 "k8s.io/kubernetes/pkg/apis/batch/v1" batchv1 "k8s.io/kubernetes/pkg/apis/batch/v1"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
@ -280,12 +281,12 @@ func (JobV1Beta1) Generate(genericParams map[string]interface{}) (runtime.Object
} }
podSpec.RestartPolicy = restartPolicy podSpec.RestartPolicy = restartPolicy
job := extensions.Job{ job := batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: name, Name: name,
Labels: labels, Labels: labels,
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: labels, MatchLabels: labels,
}, },

View File

@ -23,6 +23,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
) )
@ -721,7 +722,7 @@ func TestGenerateDeployment(t *testing.T) {
func TestGenerateJob(t *testing.T) { func TestGenerateJob(t *testing.T) {
tests := []struct { tests := []struct {
params map[string]interface{} params map[string]interface{}
expected *extensions.Job expected *batch.Job
expectErr bool expectErr bool
}{ }{
{ {
@ -740,12 +741,12 @@ func TestGenerateJob(t *testing.T) {
"limits": "cpu=400m,memory=200Mi", "limits": "cpu=400m,memory=200Mi",
"restart": "OnFailure", "restart": "OnFailure",
}, },
expected: &extensions.Job{ expected: &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"}, Labels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar", "baz": "blah"}, MatchLabels: map[string]string{"foo": "bar", "baz": "blah"},
}, },
@ -807,8 +808,8 @@ func TestGenerateJob(t *testing.T) {
if test.expectErr && err != nil { if test.expectErr && err != nil {
continue continue
} }
if !reflect.DeepEqual(obj.(*extensions.Job), test.expected) { if !reflect.DeepEqual(obj.(*batch.Job), test.expected) {
t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*extensions.Job)) t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*batch.Job))
} }
} }
} }

View File

@ -48,7 +48,7 @@ func ScalerFor(kind unversioned.GroupKind, c client.Interface) (Scaler, error) {
case extensions.Kind("ReplicaSet"): case extensions.Kind("ReplicaSet"):
return &ReplicaSetScaler{c.Extensions()}, nil return &ReplicaSetScaler{c.Extensions()}, nil
case extensions.Kind("Job"), batch.Kind("Job"): case extensions.Kind("Job"), batch.Kind("Job"):
return &JobScaler{c.Extensions()}, nil // Either kind of job can be scaled with Extensions interface. return &JobScaler{c.Batch()}, nil // Either kind of job can be scaled with Batch interface.
case extensions.Kind("Deployment"): case extensions.Kind("Deployment"):
return &DeploymentScaler{c.Extensions()}, nil return &DeploymentScaler{c.Extensions()}, nil
} }
@ -252,7 +252,7 @@ func (scaler *ReplicaSetScaler) Scale(namespace, name string, newSize uint, prec
} }
// ValidateJob ensures that the preconditions match. Returns nil if they are valid, an error otherwise. // ValidateJob ensures that the preconditions match. Returns nil if they are valid, an error otherwise.
func (precondition *ScalePrecondition) ValidateJob(job *extensions.Job) error { func (precondition *ScalePrecondition) ValidateJob(job *batch.Job) error {
if precondition.Size != -1 && job.Spec.Parallelism == nil { if precondition.Size != -1 && job.Spec.Parallelism == nil {
return PreconditionError{"parallelism", strconv.Itoa(precondition.Size), "nil"} return PreconditionError{"parallelism", strconv.Itoa(precondition.Size), "nil"}
} }
@ -266,7 +266,7 @@ func (precondition *ScalePrecondition) ValidateJob(job *extensions.Job) error {
} }
type JobScaler struct { type JobScaler struct {
c client.ExtensionsInterface c client.BatchInterface
} }
// ScaleSimple is responsible for updating job's parallelism. // ScaleSimple is responsible for updating job's parallelism.

View File

@ -22,6 +22,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
kerrors "k8s.io/kubernetes/pkg/api/errors" kerrors "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient" "k8s.io/kubernetes/pkg/client/unversioned/testclient"
@ -252,17 +253,17 @@ type ErrorJobs struct {
invalid bool invalid bool
} }
func (c *ErrorJobs) Update(job *extensions.Job) (*extensions.Job, error) { func (c *ErrorJobs) Update(job *batch.Job) (*batch.Job, error) {
if c.invalid { if c.invalid {
return nil, kerrors.NewInvalid(extensions.Kind(job.Kind), job.Name, nil) return nil, kerrors.NewInvalid(batch.Kind(job.Kind), job.Name, nil)
} }
return nil, errors.New("Job update failure") return nil, errors.New("Job update failure")
} }
func (c *ErrorJobs) Get(name string) (*extensions.Job, error) { func (c *ErrorJobs) Get(name string) (*batch.Job, error) {
zero := 0 zero := 0
return &extensions.Job{ return &batch.Job{
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &zero, Parallelism: &zero,
}, },
}, nil }, nil
@ -316,7 +317,7 @@ func TestJobScale(t *testing.T) {
if action, ok := actions[0].(testclient.GetAction); !ok || action.GetResource() != "jobs" || action.GetName() != name { if action, ok := actions[0].(testclient.GetAction); !ok || action.GetResource() != "jobs" || action.GetName() != name {
t.Errorf("unexpected action: %v, expected get-replicationController %s", actions[0], name) t.Errorf("unexpected action: %v, expected get-replicationController %s", actions[0], name)
} }
if action, ok := actions[1].(testclient.UpdateAction); !ok || action.GetResource() != "jobs" || *action.GetObject().(*extensions.Job).Spec.Parallelism != int(count) { if action, ok := actions[1].(testclient.UpdateAction); !ok || action.GetResource() != "jobs" || *action.GetObject().(*batch.Job).Spec.Parallelism != int(count) {
t.Errorf("unexpected action %v, expected update-job with parallelism = %d", actions[1], count) t.Errorf("unexpected action %v, expected update-job with parallelism = %d", actions[1], count)
} }
} }
@ -342,8 +343,8 @@ func TestJobScaleInvalid(t *testing.T) {
func TestJobScaleFailsPreconditions(t *testing.T) { func TestJobScaleFailsPreconditions(t *testing.T) {
ten := 10 ten := 10
fake := testclient.NewSimpleFake(&extensions.Job{ fake := testclient.NewSimpleFake(&batch.Job{
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &ten, Parallelism: &ten,
}, },
}) })
@ -366,7 +367,7 @@ func TestValidateJob(t *testing.T) {
zero, ten, twenty := 0, 10, 20 zero, ten, twenty := 0, 10, 20
tests := []struct { tests := []struct {
preconditions ScalePrecondition preconditions ScalePrecondition
job extensions.Job job batch.Job
expectError bool expectError bool
test string test string
}{ }{
@ -377,11 +378,11 @@ func TestValidateJob(t *testing.T) {
}, },
{ {
preconditions: ScalePrecondition{-1, ""}, preconditions: ScalePrecondition{-1, ""},
job: extensions.Job{ job: batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
ResourceVersion: "foo", ResourceVersion: "foo",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &ten, Parallelism: &ten,
}, },
}, },
@ -390,11 +391,11 @@ func TestValidateJob(t *testing.T) {
}, },
{ {
preconditions: ScalePrecondition{0, ""}, preconditions: ScalePrecondition{0, ""},
job: extensions.Job{ job: batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
ResourceVersion: "foo", ResourceVersion: "foo",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &zero, Parallelism: &zero,
}, },
}, },
@ -403,11 +404,11 @@ func TestValidateJob(t *testing.T) {
}, },
{ {
preconditions: ScalePrecondition{-1, "foo"}, preconditions: ScalePrecondition{-1, "foo"},
job: extensions.Job{ job: batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
ResourceVersion: "foo", ResourceVersion: "foo",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &ten, Parallelism: &ten,
}, },
}, },
@ -416,11 +417,11 @@ func TestValidateJob(t *testing.T) {
}, },
{ {
preconditions: ScalePrecondition{10, "foo"}, preconditions: ScalePrecondition{10, "foo"},
job: extensions.Job{ job: batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
ResourceVersion: "foo", ResourceVersion: "foo",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &ten, Parallelism: &ten,
}, },
}, },
@ -429,11 +430,11 @@ func TestValidateJob(t *testing.T) {
}, },
{ {
preconditions: ScalePrecondition{10, "foo"}, preconditions: ScalePrecondition{10, "foo"},
job: extensions.Job{ job: batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
ResourceVersion: "foo", ResourceVersion: "foo",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &twenty, Parallelism: &twenty,
}, },
}, },
@ -442,7 +443,7 @@ func TestValidateJob(t *testing.T) {
}, },
{ {
preconditions: ScalePrecondition{10, "foo"}, preconditions: ScalePrecondition{10, "foo"},
job: extensions.Job{ job: batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
ResourceVersion: "foo", ResourceVersion: "foo",
}, },
@ -452,11 +453,11 @@ func TestValidateJob(t *testing.T) {
}, },
{ {
preconditions: ScalePrecondition{10, "foo"}, preconditions: ScalePrecondition{10, "foo"},
job: extensions.Job{ job: batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
ResourceVersion: "bar", ResourceVersion: "bar",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &ten, Parallelism: &ten,
}, },
}, },
@ -465,11 +466,11 @@ func TestValidateJob(t *testing.T) {
}, },
{ {
preconditions: ScalePrecondition{10, "foo"}, preconditions: ScalePrecondition{10, "foo"},
job: extensions.Job{ job: batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
ResourceVersion: "bar", ResourceVersion: "bar",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &twenty, Parallelism: &twenty,
}, },
}, },

View File

@ -314,9 +314,9 @@ func (reaper *DaemonSetReaper) Stop(namespace, name string, timeout time.Duratio
} }
func (reaper *JobReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *api.DeleteOptions) error { func (reaper *JobReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *api.DeleteOptions) error {
jobs := reaper.Extensions().Jobs(namespace) jobs := reaper.Batch().Jobs(namespace)
pods := reaper.Pods(namespace) pods := reaper.Pods(namespace)
scaler, err := ScalerFor(extensions.Kind("Job"), *reaper) scaler, err := ScalerFor(batch.Kind("Job"), *reaper)
if err != nil { if err != nil {
return err return err
} }

View File

@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient" "k8s.io/kubernetes/pkg/client/unversioned/testclient"
@ -388,26 +389,26 @@ func TestJobStop(t *testing.T) {
{ {
Name: "OnlyOneJob", Name: "OnlyOneJob",
Objs: []runtime.Object{ Objs: []runtime.Object{
&extensions.Job{ // GET &batch.Job{ // GET
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: name, Name: name,
Namespace: ns, Namespace: ns,
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &zero, Parallelism: &zero,
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"k1": "v1"}, MatchLabels: map[string]string{"k1": "v1"},
}, },
}, },
}, },
&extensions.JobList{ // LIST &batch.JobList{ // LIST
Items: []extensions.Job{ Items: []batch.Job{
{ {
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: name, Name: name,
Namespace: ns, Namespace: ns,
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &zero, Parallelism: &zero,
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"k1": "v1"}, MatchLabels: map[string]string{"k1": "v1"},
@ -424,26 +425,26 @@ func TestJobStop(t *testing.T) {
{ {
Name: "JobWithDeadPods", Name: "JobWithDeadPods",
Objs: []runtime.Object{ Objs: []runtime.Object{
&extensions.Job{ // GET &batch.Job{ // GET
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: name, Name: name,
Namespace: ns, Namespace: ns,
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &zero, Parallelism: &zero,
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"k1": "v1"}, MatchLabels: map[string]string{"k1": "v1"},
}, },
}, },
}, },
&extensions.JobList{ // LIST &batch.JobList{ // LIST
Items: []extensions.Job{ Items: []batch.Job{
{ {
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: name, Name: name,
Namespace: ns, Namespace: ns,
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &zero, Parallelism: &zero,
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"k1": "v1"}, MatchLabels: map[string]string{"k1": "v1"},

View File

@ -18,7 +18,7 @@ package etcd
import ( import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/cachesize" "k8s.io/kubernetes/pkg/registry/cachesize"
@ -37,12 +37,12 @@ type REST struct {
func NewREST(opts generic.RESTOptions) (*REST, *StatusREST) { func NewREST(opts generic.RESTOptions) (*REST, *StatusREST) {
prefix := "/jobs" prefix := "/jobs"
newListFunc := func() runtime.Object { return &extensions.JobList{} } newListFunc := func() runtime.Object { return &batch.JobList{} }
storageInterface := opts.Decorator( storageInterface := opts.Decorator(
opts.Storage, cachesize.GetWatchCacheSizeByResource(cachesize.Jobs), &extensions.Job{}, prefix, job.Strategy, newListFunc) opts.Storage, cachesize.GetWatchCacheSizeByResource(cachesize.Jobs), &batch.Job{}, prefix, job.Strategy, newListFunc)
store := &etcdgeneric.Etcd{ store := &etcdgeneric.Etcd{
NewFunc: func() runtime.Object { return &extensions.Job{} }, NewFunc: func() runtime.Object { return &batch.Job{} },
// NewListFunc returns an object capable of storing results of an etcd list. // NewListFunc returns an object capable of storing results of an etcd list.
NewListFunc: newListFunc, NewListFunc: newListFunc,
@ -58,13 +58,13 @@ func NewREST(opts generic.RESTOptions) (*REST, *StatusREST) {
}, },
// Retrieve the name field of a job // Retrieve the name field of a job
ObjectNameFunc: func(obj runtime.Object) (string, error) { ObjectNameFunc: func(obj runtime.Object) (string, error) {
return obj.(*extensions.Job).Name, nil return obj.(*batch.Job).Name, nil
}, },
// Used to match objects based on labels/fields for list and watch // Used to match objects based on labels/fields for list and watch
PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher { PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
return job.MatchJob(label, field) return job.MatchJob(label, field)
}, },
QualifiedResource: extensions.Resource("jobs"), QualifiedResource: batch.Resource("jobs"),
DeleteCollectionWorkers: opts.DeleteCollectionWorkers, DeleteCollectionWorkers: opts.DeleteCollectionWorkers,
// Used to validate job creation // Used to validate job creation
@ -89,7 +89,7 @@ type StatusREST struct {
} }
func (r *StatusREST) New() runtime.Object { func (r *StatusREST) New() runtime.Object {
return &extensions.Job{} return &batch.Job{}
} }
// Update alters the status subset of an object. // Update alters the status subset of an object.

View File

@ -21,9 +21,8 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
// Ensure that extensions/v1beta1 package is initialized.
_ "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
@ -39,15 +38,15 @@ func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer)
return jobStorage, statusStorage, server return jobStorage, statusStorage, server
} }
func validNewJob() *extensions.Job { func validNewJob() *batch.Job {
completions := 1 completions := 1
parallelism := 1 parallelism := 1
return &extensions.Job{ return &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
Namespace: "default", Namespace: "default",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Completions: &completions, Completions: &completions,
Parallelism: &parallelism, Parallelism: &parallelism,
Selector: &unversioned.LabelSelector{ Selector: &unversioned.LabelSelector{
@ -84,8 +83,8 @@ func TestCreate(t *testing.T) {
// valid // valid
validJob, validJob,
// invalid (empty selector) // invalid (empty selector)
&extensions.Job{ &batch.Job{
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Completions: validJob.Spec.Completions, Completions: validJob.Spec.Completions,
Selector: &unversioned.LabelSelector{}, Selector: &unversioned.LabelSelector{},
Template: validJob.Spec.Template, Template: validJob.Spec.Template,
@ -104,18 +103,18 @@ func TestUpdate(t *testing.T) {
validNewJob(), validNewJob(),
// updateFunc // updateFunc
func(obj runtime.Object) runtime.Object { func(obj runtime.Object) runtime.Object {
object := obj.(*extensions.Job) object := obj.(*batch.Job)
object.Spec.Parallelism = &two object.Spec.Parallelism = &two
return object return object
}, },
// invalid updateFunc // invalid updateFunc
func(obj runtime.Object) runtime.Object { func(obj runtime.Object) runtime.Object {
object := obj.(*extensions.Job) object := obj.(*batch.Job)
object.Spec.Selector = &unversioned.LabelSelector{} object.Spec.Selector = &unversioned.LabelSelector{}
return object return object
}, },
func(obj runtime.Object) runtime.Object { func(obj runtime.Object) runtime.Object {
object := obj.(*extensions.Job) object := obj.(*batch.Job)
object.Spec.Completions = &two object.Spec.Completions = &two
return object return object
}, },

View File

@ -22,8 +22,8 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions/validation" "k8s.io/kubernetes/pkg/apis/batch/validation"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
@ -47,20 +47,20 @@ func (jobStrategy) NamespaceScoped() bool {
// PrepareForCreate clears the status of a job before creation. // PrepareForCreate clears the status of a job before creation.
func (jobStrategy) PrepareForCreate(obj runtime.Object) { func (jobStrategy) PrepareForCreate(obj runtime.Object) {
job := obj.(*extensions.Job) job := obj.(*batch.Job)
job.Status = extensions.JobStatus{} job.Status = batch.JobStatus{}
} }
// PrepareForUpdate clears fields that are not allowed to be set by end users on update. // PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func (jobStrategy) PrepareForUpdate(obj, old runtime.Object) { func (jobStrategy) PrepareForUpdate(obj, old runtime.Object) {
newJob := obj.(*extensions.Job) newJob := obj.(*batch.Job)
oldJob := old.(*extensions.Job) oldJob := old.(*batch.Job)
newJob.Status = oldJob.Status newJob.Status = oldJob.Status
} }
// Validate validates a new job. // Validate validates a new job.
func (jobStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { func (jobStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList {
job := obj.(*extensions.Job) job := obj.(*batch.Job)
// TODO: move UID generation earlier and do this in defaulting logic? // TODO: move UID generation earlier and do this in defaulting logic?
if job.Spec.ManualSelector == nil || *job.Spec.ManualSelector == false { if job.Spec.ManualSelector == nil || *job.Spec.ManualSelector == false {
generateSelector(job) generateSelector(job)
@ -71,7 +71,7 @@ func (jobStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList
// generateSelector adds a selector to a job and labels to its template // generateSelector adds a selector to a job and labels to its template
// which can be used to uniquely identify the pods created by that job, // which can be used to uniquely identify the pods created by that job,
// if the user has requested this behavior. // if the user has requested this behavior.
func generateSelector(obj *extensions.Job) { func generateSelector(obj *batch.Job) {
if obj.Spec.Template.Labels == nil { if obj.Spec.Template.Labels == nil {
obj.Spec.Template.Labels = make(map[string]string) obj.Spec.Template.Labels = make(map[string]string)
} }
@ -133,8 +133,8 @@ func (jobStrategy) AllowCreateOnUpdate() bool {
// ValidateUpdate is the default update validation for an end user. // ValidateUpdate is the default update validation for an end user.
func (jobStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { func (jobStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList {
validationErrorList := validation.ValidateJob(obj.(*extensions.Job)) validationErrorList := validation.ValidateJob(obj.(*batch.Job))
updateErrorList := validation.ValidateJobUpdate(obj.(*extensions.Job), old.(*extensions.Job)) updateErrorList := validation.ValidateJobUpdate(obj.(*batch.Job), old.(*batch.Job))
return append(validationErrorList, updateErrorList...) return append(validationErrorList, updateErrorList...)
} }
@ -145,17 +145,17 @@ type jobStatusStrategy struct {
var StatusStrategy = jobStatusStrategy{Strategy} var StatusStrategy = jobStatusStrategy{Strategy}
func (jobStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { func (jobStatusStrategy) PrepareForUpdate(obj, old runtime.Object) {
newJob := obj.(*extensions.Job) newJob := obj.(*batch.Job)
oldJob := old.(*extensions.Job) oldJob := old.(*batch.Job)
newJob.Spec = oldJob.Spec newJob.Spec = oldJob.Spec
} }
func (jobStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { func (jobStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList {
return validation.ValidateJobUpdateStatus(obj.(*extensions.Job), old.(*extensions.Job)) return validation.ValidateJobUpdateStatus(obj.(*batch.Job), old.(*batch.Job))
} }
// JobSelectableFields returns a field set that represents the object for matching purposes. // JobSelectableFields returns a field set that represents the object for matching purposes.
func JobToSelectableFields(job *extensions.Job) fields.Set { func JobToSelectableFields(job *batch.Job) fields.Set {
objectMetaFieldsSet := generic.ObjectMetaFieldsSet(job.ObjectMeta, true) objectMetaFieldsSet := generic.ObjectMetaFieldsSet(job.ObjectMeta, true)
specificFieldsSet := fields.Set{ specificFieldsSet := fields.Set{
"status.successful": strconv.Itoa(job.Status.Succeeded), "status.successful": strconv.Itoa(job.Status.Succeeded),
@ -171,7 +171,7 @@ func MatchJob(label labels.Selector, field fields.Selector) generic.Matcher {
Label: label, Label: label,
Field: field, Field: field,
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
job, ok := obj.(*extensions.Job) job, ok := obj.(*batch.Job)
if !ok { if !ok {
return nil, nil, fmt.Errorf("Given object is not a job.") return nil, nil, fmt.Errorf("Given object is not a job.")
} }

View File

@ -24,7 +24,7 @@ import (
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/types"
) )
@ -57,17 +57,17 @@ func TestJobStrategy(t *testing.T) {
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
}, },
} }
job := &extensions.Job{ job := &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "myjob", Name: "myjob",
Namespace: api.NamespaceDefault, Namespace: api.NamespaceDefault,
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: validSelector, Selector: validSelector,
Template: validPodTemplateSpec, Template: validPodTemplateSpec,
ManualSelector: newBool(true), ManualSelector: newBool(true),
}, },
Status: extensions.JobStatus{ Status: batch.JobStatus{
Active: 11, Active: 11,
}, },
} }
@ -81,12 +81,12 @@ func TestJobStrategy(t *testing.T) {
t.Errorf("Unexpected error validating %v", errs) t.Errorf("Unexpected error validating %v", errs)
} }
parallelism := 10 parallelism := 10
updatedJob := &extensions.Job{ updatedJob := &batch.Job{
ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "4"}, ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "4"},
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &parallelism, Parallelism: &parallelism,
}, },
Status: extensions.JobStatus{ Status: batch.JobStatus{
Active: 11, Active: 11,
}, },
} }
@ -114,13 +114,13 @@ func TestJobStrategyWithGeneration(t *testing.T) {
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
}, },
} }
job := &extensions.Job{ job := &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "myjob2", Name: "myjob2",
Namespace: api.NamespaceDefault, Namespace: api.NamespaceDefault,
UID: theUID, UID: theUID,
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: nil, Selector: nil,
Template: validPodTemplateSpec, Template: validPodTemplateSpec,
}, },
@ -175,33 +175,33 @@ func TestJobStatusStrategy(t *testing.T) {
} }
oldParallelism := 10 oldParallelism := 10
newParallelism := 11 newParallelism := 11
oldJob := &extensions.Job{ oldJob := &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "myjob", Name: "myjob",
Namespace: api.NamespaceDefault, Namespace: api.NamespaceDefault,
ResourceVersion: "10", ResourceVersion: "10",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: validSelector, Selector: validSelector,
Template: validPodTemplateSpec, Template: validPodTemplateSpec,
Parallelism: &oldParallelism, Parallelism: &oldParallelism,
}, },
Status: extensions.JobStatus{ Status: batch.JobStatus{
Active: 11, Active: 11,
}, },
} }
newJob := &extensions.Job{ newJob := &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "myjob", Name: "myjob",
Namespace: api.NamespaceDefault, Namespace: api.NamespaceDefault,
ResourceVersion: "9", ResourceVersion: "9",
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Selector: validSelector, Selector: validSelector,
Template: validPodTemplateSpec, Template: validPodTemplateSpec,
Parallelism: &newParallelism, Parallelism: &newParallelism,
}, },
Status: extensions.JobStatus{ Status: batch.JobStatus{
Active: 12, Active: 12,
}, },
} }
@ -226,7 +226,7 @@ func TestSelectableFieldLabelConversions(t *testing.T) {
apitesting.TestSelectableFieldLabelConversionsOfKind(t, apitesting.TestSelectableFieldLabelConversionsOfKind(t,
testapi.Extensions.GroupVersion().String(), testapi.Extensions.GroupVersion().String(),
"Job", "Job",
labels.Set(JobToSelectableFields(&extensions.Job{})), labels.Set(JobToSelectableFields(&batch.Job{})),
nil, nil,
) )
} }

View File

@ -25,7 +25,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/batch"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
@ -128,7 +128,7 @@ var _ = framework.KubeDescribe("V1Job", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("scale job up") By("scale job up")
scaler, err := kubectl.ScalerFor(extensions.Kind("Job"), f.Client) scaler, err := kubectl.ScalerFor(batch.Kind("Job"), f.Client)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
waitForScale := kubectl.NewRetryParams(5*time.Second, 1*time.Minute) waitForScale := kubectl.NewRetryParams(5*time.Second, 1*time.Minute)
waitForReplicas := kubectl.NewRetryParams(5*time.Second, 5*time.Minute) waitForReplicas := kubectl.NewRetryParams(5*time.Second, 5*time.Minute)
@ -153,7 +153,7 @@ var _ = framework.KubeDescribe("V1Job", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("scale job down") By("scale job down")
scaler, err := kubectl.ScalerFor(extensions.Kind("Job"), f.Client) scaler, err := kubectl.ScalerFor(batch.Kind("Job"), f.Client)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
waitForScale := kubectl.NewRetryParams(5*time.Second, 1*time.Minute) waitForScale := kubectl.NewRetryParams(5*time.Second, 1*time.Minute)
waitForReplicas := kubectl.NewRetryParams(5*time.Second, 5*time.Minute) waitForReplicas := kubectl.NewRetryParams(5*time.Second, 5*time.Minute)
@ -176,7 +176,7 @@ var _ = framework.KubeDescribe("V1Job", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("delete a job") By("delete a job")
reaper, err := kubectl.ReaperFor(extensions.Kind("Job"), f.Client) reaper, err := kubectl.ReaperFor(batch.Kind("Job"), f.Client)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
timeout := 1 * time.Minute timeout := 1 * time.Minute
err = reaper.Stop(f.Namespace.Name, job.Name, timeout, api.NewDeleteOptions(0)) err = reaper.Stop(f.Namespace.Name, job.Name, timeout, api.NewDeleteOptions(0))
@ -203,12 +203,12 @@ var _ = framework.KubeDescribe("V1Job", func() {
}) })
// newTestV1Job returns a job which does one of several testing behaviors. // newTestV1Job returns a job which does one of several testing behaviors.
func newTestV1Job(behavior, name string, rPol api.RestartPolicy, parallelism, completions int) *extensions.Job { func newTestV1Job(behavior, name string, rPol api.RestartPolicy, parallelism, completions int) *batch.Job {
job := &extensions.Job{ job := &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: name, Name: name,
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &parallelism, Parallelism: &parallelism,
Completions: &completions, Completions: &completions,
Template: api.PodTemplateSpec{ Template: api.PodTemplateSpec{
@ -264,7 +264,7 @@ func newTestV1Job(behavior, name string, rPol api.RestartPolicy, parallelism, co
return job return job
} }
func createV1Job(c *client.Client, ns string, job *extensions.Job) (*extensions.Job, error) { func createV1Job(c *client.Client, ns string, job *batch.Job) (*batch.Job, error) {
return c.Batch().Jobs(ns).Create(job) return c.Batch().Jobs(ns).Create(job)
} }
@ -310,7 +310,7 @@ func waitForV1JobFail(c *client.Client, ns, jobName string) error {
return false, err return false, err
} }
for _, c := range curr.Status.Conditions { for _, c := range curr.Status.Conditions {
if c.Type == extensions.JobFailed && c.Status == api.ConditionTrue { if c.Type == batch.JobFailed && c.Status == api.ConditionTrue {
return true, nil return true, nil
} }
} }

View File

@ -21,7 +21,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/batch"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
@ -124,7 +124,7 @@ var _ = framework.KubeDescribe("Job", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("scale job up") By("scale job up")
scaler, err := kubectl.ScalerFor(extensions.Kind("Job"), f.Client) scaler, err := kubectl.ScalerFor(batch.Kind("Job"), f.Client)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
waitForScale := kubectl.NewRetryParams(5*time.Second, 1*time.Minute) waitForScale := kubectl.NewRetryParams(5*time.Second, 1*time.Minute)
waitForReplicas := kubectl.NewRetryParams(5*time.Second, 5*time.Minute) waitForReplicas := kubectl.NewRetryParams(5*time.Second, 5*time.Minute)
@ -149,7 +149,7 @@ var _ = framework.KubeDescribe("Job", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("scale job down") By("scale job down")
scaler, err := kubectl.ScalerFor(extensions.Kind("Job"), f.Client) scaler, err := kubectl.ScalerFor(batch.Kind("Job"), f.Client)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
waitForScale := kubectl.NewRetryParams(5*time.Second, 1*time.Minute) waitForScale := kubectl.NewRetryParams(5*time.Second, 1*time.Minute)
waitForReplicas := kubectl.NewRetryParams(5*time.Second, 5*time.Minute) waitForReplicas := kubectl.NewRetryParams(5*time.Second, 5*time.Minute)
@ -172,7 +172,7 @@ var _ = framework.KubeDescribe("Job", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("delete a job") By("delete a job")
reaper, err := kubectl.ReaperFor(extensions.Kind("Job"), f.Client) reaper, err := kubectl.ReaperFor(batch.Kind("Job"), f.Client)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
timeout := 1 * time.Minute timeout := 1 * time.Minute
err = reaper.Stop(f.Namespace.Name, job.Name, timeout, api.NewDeleteOptions(0)) err = reaper.Stop(f.Namespace.Name, job.Name, timeout, api.NewDeleteOptions(0))
@ -199,12 +199,12 @@ var _ = framework.KubeDescribe("Job", func() {
}) })
// newTestJob returns a job which does one of several testing behaviors. // newTestJob returns a job which does one of several testing behaviors.
func newTestJob(behavior, name string, rPol api.RestartPolicy, parallelism, completions int) *extensions.Job { func newTestJob(behavior, name string, rPol api.RestartPolicy, parallelism, completions int) *batch.Job {
job := &extensions.Job{ job := &batch.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: name, Name: name,
}, },
Spec: extensions.JobSpec{ Spec: batch.JobSpec{
Parallelism: &parallelism, Parallelism: &parallelism,
Completions: &completions, Completions: &completions,
ManualSelector: newBool(true), ManualSelector: newBool(true),
@ -261,7 +261,7 @@ func newTestJob(behavior, name string, rPol api.RestartPolicy, parallelism, comp
return job return job
} }
func createJob(c *client.Client, ns string, job *extensions.Job) (*extensions.Job, error) { func createJob(c *client.Client, ns string, job *batch.Job) (*batch.Job, error) {
return c.Extensions().Jobs(ns).Create(job) return c.Extensions().Jobs(ns).Create(job)
} }
@ -307,7 +307,7 @@ func waitForJobFail(c *client.Client, ns, jobName string) error {
return false, err return false, err
} }
for _, c := range curr.Status.Conditions { for _, c := range curr.Status.Conditions {
if c.Type == extensions.JobFailed && c.Status == api.ConditionTrue { if c.Type == batch.JobFailed && c.Status == api.ConditionTrue {
return true, nil return true, nil
} }
} }