mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 05:27:21 +00:00
New Job resource
This commit is contained in:
parent
90ba96d486
commit
e55c59e8c2
@ -986,6 +986,121 @@ func deepCopy_expapi_HorizontalPodAutoscalerStatus(in HorizontalPodAutoscalerSta
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deepCopy_expapi_Job(in Job, out *Job, c *conversion.Cloner) error {
|
||||||
|
if err := deepCopy_api_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deepCopy_expapi_JobSpec(in.Spec, &out.Spec, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deepCopy_expapi_JobStatus(in.Status, &out.Status, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopy_expapi_JobCondition(in JobCondition, out *JobCondition, c *conversion.Cloner) error {
|
||||||
|
out.Type = in.Type
|
||||||
|
out.Status = in.Status
|
||||||
|
if err := deepCopy_util_Time(in.LastProbeTime, &out.LastProbeTime, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deepCopy_util_Time(in.LastTransitionTime, &out.LastTransitionTime, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out.Reason = in.Reason
|
||||||
|
out.Message = in.Message
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopy_expapi_JobList(in JobList, out *JobList, c *conversion.Cloner) error {
|
||||||
|
if err := deepCopy_api_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deepCopy_api_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if in.Items != nil {
|
||||||
|
out.Items = make([]Job, len(in.Items))
|
||||||
|
for i := range in.Items {
|
||||||
|
if err := deepCopy_expapi_Job(in.Items[i], &out.Items[i], c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Items = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopy_expapi_JobSpec(in JobSpec, out *JobSpec, c *conversion.Cloner) error {
|
||||||
|
if in.Parallelism != nil {
|
||||||
|
out.Parallelism = new(int)
|
||||||
|
*out.Parallelism = *in.Parallelism
|
||||||
|
} else {
|
||||||
|
out.Parallelism = nil
|
||||||
|
}
|
||||||
|
if in.Completions != nil {
|
||||||
|
out.Completions = new(int)
|
||||||
|
*out.Completions = *in.Completions
|
||||||
|
} else {
|
||||||
|
out.Completions = nil
|
||||||
|
}
|
||||||
|
if in.Selector != nil {
|
||||||
|
out.Selector = make(map[string]string)
|
||||||
|
for key, val := range in.Selector {
|
||||||
|
out.Selector[key] = val
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Selector = nil
|
||||||
|
}
|
||||||
|
if in.Template != nil {
|
||||||
|
out.Template = new(api.PodTemplateSpec)
|
||||||
|
if err := deepCopy_api_PodTemplateSpec(*in.Template, out.Template, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Template = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopy_expapi_JobStatus(in JobStatus, out *JobStatus, c *conversion.Cloner) error {
|
||||||
|
if in.Conditions != nil {
|
||||||
|
out.Conditions = make([]JobCondition, len(in.Conditions))
|
||||||
|
for i := range in.Conditions {
|
||||||
|
if err := deepCopy_expapi_JobCondition(in.Conditions[i], &out.Conditions[i], c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Conditions = nil
|
||||||
|
}
|
||||||
|
if in.StartTime != nil {
|
||||||
|
out.StartTime = new(util.Time)
|
||||||
|
if err := deepCopy_util_Time(*in.StartTime, out.StartTime, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.StartTime = nil
|
||||||
|
}
|
||||||
|
if in.CompletionTime != nil {
|
||||||
|
out.CompletionTime = new(util.Time)
|
||||||
|
if err := deepCopy_util_Time(*in.CompletionTime, out.CompletionTime, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.CompletionTime = nil
|
||||||
|
}
|
||||||
|
out.Active = in.Active
|
||||||
|
out.Successful = in.Successful
|
||||||
|
out.Unsuccessful = in.Unsuccessful
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func deepCopy_expapi_ReplicationControllerDummy(in ReplicationControllerDummy, out *ReplicationControllerDummy, c *conversion.Cloner) error {
|
func deepCopy_expapi_ReplicationControllerDummy(in ReplicationControllerDummy, out *ReplicationControllerDummy, c *conversion.Cloner) error {
|
||||||
if err := deepCopy_api_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
if err := deepCopy_api_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1206,6 +1321,11 @@ func init() {
|
|||||||
deepCopy_expapi_HorizontalPodAutoscalerList,
|
deepCopy_expapi_HorizontalPodAutoscalerList,
|
||||||
deepCopy_expapi_HorizontalPodAutoscalerSpec,
|
deepCopy_expapi_HorizontalPodAutoscalerSpec,
|
||||||
deepCopy_expapi_HorizontalPodAutoscalerStatus,
|
deepCopy_expapi_HorizontalPodAutoscalerStatus,
|
||||||
|
deepCopy_expapi_Job,
|
||||||
|
deepCopy_expapi_JobCondition,
|
||||||
|
deepCopy_expapi_JobList,
|
||||||
|
deepCopy_expapi_JobSpec,
|
||||||
|
deepCopy_expapi_JobStatus,
|
||||||
deepCopy_expapi_ReplicationControllerDummy,
|
deepCopy_expapi_ReplicationControllerDummy,
|
||||||
deepCopy_expapi_ResourceConsumption,
|
deepCopy_expapi_ResourceConsumption,
|
||||||
deepCopy_expapi_RollingUpdateDeployment,
|
deepCopy_expapi_RollingUpdateDeployment,
|
||||||
|
@ -32,6 +32,8 @@ func addKnownTypes() {
|
|||||||
&DeploymentList{},
|
&DeploymentList{},
|
||||||
&HorizontalPodAutoscaler{},
|
&HorizontalPodAutoscaler{},
|
||||||
&HorizontalPodAutoscalerList{},
|
&HorizontalPodAutoscalerList{},
|
||||||
|
&Job{},
|
||||||
|
&JobList{},
|
||||||
&ReplicationControllerDummy{},
|
&ReplicationControllerDummy{},
|
||||||
&Scale{},
|
&Scale{},
|
||||||
&ThirdPartyResource{},
|
&ThirdPartyResource{},
|
||||||
@ -47,6 +49,8 @@ func (*Deployment) IsAnAPIObject() {}
|
|||||||
func (*DeploymentList) IsAnAPIObject() {}
|
func (*DeploymentList) IsAnAPIObject() {}
|
||||||
func (*HorizontalPodAutoscaler) IsAnAPIObject() {}
|
func (*HorizontalPodAutoscaler) IsAnAPIObject() {}
|
||||||
func (*HorizontalPodAutoscalerList) IsAnAPIObject() {}
|
func (*HorizontalPodAutoscalerList) IsAnAPIObject() {}
|
||||||
|
func (*Job) IsAnAPIObject() {}
|
||||||
|
func (*JobList) IsAnAPIObject() {}
|
||||||
func (*ReplicationControllerDummy) IsAnAPIObject() {}
|
func (*ReplicationControllerDummy) IsAnAPIObject() {}
|
||||||
func (*Scale) IsAnAPIObject() {}
|
func (*Scale) IsAnAPIObject() {}
|
||||||
func (*ThirdPartyResource) IsAnAPIObject() {}
|
func (*ThirdPartyResource) IsAnAPIObject() {}
|
||||||
|
@ -362,3 +362,102 @@ type ThirdPartyResourceDataList struct {
|
|||||||
// Items is a list of third party objects
|
// Items is a list of third party objects
|
||||||
Items []ThirdPartyResourceData `json:"items"`
|
Items []ThirdPartyResourceData `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Job represents the configuration of a single job.
|
||||||
|
type Job struct {
|
||||||
|
api.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 {
|
||||||
|
api.TypeMeta `json:",inline"`
|
||||||
|
// Standard list metadata
|
||||||
|
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
|
||||||
|
api.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. Defaults to 1.
|
||||||
|
Completions *int `json:"completions,omitempty"`
|
||||||
|
|
||||||
|
// Selector is a label query over pods that should match the pod count.
|
||||||
|
Selector map[string]string `json:"selector"`
|
||||||
|
|
||||||
|
// 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 *util.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 *util.Time `json:"completionTime,omitempty"`
|
||||||
|
|
||||||
|
// Active is the number of actively running pods.
|
||||||
|
Active int `json:"active,omitempty"`
|
||||||
|
|
||||||
|
// Successful is the number of pods which reached Phase Succeeded.
|
||||||
|
Successful int `json:"successful,omitempty"`
|
||||||
|
|
||||||
|
// Unsuccessful is the number of pods failures, this applies only to jobs
|
||||||
|
// created with RestartPolicyNever, otherwise this value will always be 0.
|
||||||
|
Unsuccessful int `json:"unsuccessful,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JobConditionType string
|
||||||
|
|
||||||
|
// These are valid conditions of a job.
|
||||||
|
const (
|
||||||
|
// JobComplete means the job has completed its execution.
|
||||||
|
JobComplete JobConditionType = "Complete"
|
||||||
|
)
|
||||||
|
|
||||||
|
// JobCondition describes current state of a job.
|
||||||
|
type JobCondition struct {
|
||||||
|
// Type of job condition, currently only Complete.
|
||||||
|
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 util.Time `json:"lastProbeTime,omitempty"`
|
||||||
|
// Last time the condition transit from one status to another.
|
||||||
|
LastTransitionTime util.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"`
|
||||||
|
}
|
||||||
|
@ -1788,6 +1788,134 @@ func convert_expapi_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutoscalerS
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convert_expapi_Job_To_v1_Job(in *expapi.Job, out *Job, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*expapi.Job))(in)
|
||||||
|
}
|
||||||
|
if err := convert_api_TypeMeta_To_v1_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := convert_api_ObjectMeta_To_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := convert_expapi_JobSpec_To_v1_JobSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := convert_expapi_JobStatus_To_v1_JobStatus(&in.Status, &out.Status, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_expapi_JobCondition_To_v1_JobCondition(in *expapi.JobCondition, out *JobCondition, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*expapi.JobCondition))(in)
|
||||||
|
}
|
||||||
|
out.Type = JobConditionType(in.Type)
|
||||||
|
out.Status = v1.ConditionStatus(in.Status)
|
||||||
|
if err := s.Convert(&in.LastProbeTime, &out.LastProbeTime, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out.Reason = in.Reason
|
||||||
|
out.Message = in.Message
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_expapi_JobList_To_v1_JobList(in *expapi.JobList, out *JobList, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*expapi.JobList))(in)
|
||||||
|
}
|
||||||
|
if err := convert_api_TypeMeta_To_v1_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := convert_api_ListMeta_To_v1_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if in.Items != nil {
|
||||||
|
out.Items = make([]Job, len(in.Items))
|
||||||
|
for i := range in.Items {
|
||||||
|
if err := convert_expapi_Job_To_v1_Job(&in.Items[i], &out.Items[i], s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Items = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_expapi_JobSpec_To_v1_JobSpec(in *expapi.JobSpec, out *JobSpec, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*expapi.JobSpec))(in)
|
||||||
|
}
|
||||||
|
if in.Parallelism != nil {
|
||||||
|
out.Parallelism = new(int)
|
||||||
|
*out.Parallelism = *in.Parallelism
|
||||||
|
} else {
|
||||||
|
out.Parallelism = nil
|
||||||
|
}
|
||||||
|
if in.Completions != nil {
|
||||||
|
out.Completions = new(int)
|
||||||
|
*out.Completions = *in.Completions
|
||||||
|
} else {
|
||||||
|
out.Completions = nil
|
||||||
|
}
|
||||||
|
if in.Selector != nil {
|
||||||
|
out.Selector = make(map[string]string)
|
||||||
|
for key, val := range in.Selector {
|
||||||
|
out.Selector[key] = val
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Selector = nil
|
||||||
|
}
|
||||||
|
if in.Template != nil {
|
||||||
|
out.Template = new(v1.PodTemplateSpec)
|
||||||
|
if err := convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(in.Template, out.Template, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Template = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_expapi_JobStatus_To_v1_JobStatus(in *expapi.JobStatus, out *JobStatus, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*expapi.JobStatus))(in)
|
||||||
|
}
|
||||||
|
if in.Conditions != nil {
|
||||||
|
out.Conditions = make([]JobCondition, len(in.Conditions))
|
||||||
|
for i := range in.Conditions {
|
||||||
|
if err := convert_expapi_JobCondition_To_v1_JobCondition(&in.Conditions[i], &out.Conditions[i], s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Conditions = nil
|
||||||
|
}
|
||||||
|
if in.StartTime != nil {
|
||||||
|
if err := s.Convert(&in.StartTime, &out.StartTime, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.StartTime = nil
|
||||||
|
}
|
||||||
|
if in.CompletionTime != nil {
|
||||||
|
if err := s.Convert(&in.CompletionTime, &out.CompletionTime, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.CompletionTime = nil
|
||||||
|
}
|
||||||
|
out.Active = in.Active
|
||||||
|
out.Successful = in.Successful
|
||||||
|
out.Unsuccessful = in.Unsuccessful
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func convert_expapi_ReplicationControllerDummy_To_v1_ReplicationControllerDummy(in *expapi.ReplicationControllerDummy, out *ReplicationControllerDummy, s conversion.Scope) error {
|
func convert_expapi_ReplicationControllerDummy_To_v1_ReplicationControllerDummy(in *expapi.ReplicationControllerDummy, out *ReplicationControllerDummy, s conversion.Scope) error {
|
||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
defaulting.(func(*expapi.ReplicationControllerDummy))(in)
|
defaulting.(func(*expapi.ReplicationControllerDummy))(in)
|
||||||
@ -2176,6 +2304,134 @@ func convert_v1_HorizontalPodAutoscalerStatus_To_expapi_HorizontalPodAutoscalerS
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convert_v1_Job_To_expapi_Job(in *Job, out *expapi.Job, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*Job))(in)
|
||||||
|
}
|
||||||
|
if err := convert_v1_TypeMeta_To_api_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := convert_v1_ObjectMeta_To_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := convert_v1_JobSpec_To_expapi_JobSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := convert_v1_JobStatus_To_expapi_JobStatus(&in.Status, &out.Status, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_v1_JobCondition_To_expapi_JobCondition(in *JobCondition, out *expapi.JobCondition, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*JobCondition))(in)
|
||||||
|
}
|
||||||
|
out.Type = expapi.JobConditionType(in.Type)
|
||||||
|
out.Status = api.ConditionStatus(in.Status)
|
||||||
|
if err := s.Convert(&in.LastProbeTime, &out.LastProbeTime, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out.Reason = in.Reason
|
||||||
|
out.Message = in.Message
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_v1_JobList_To_expapi_JobList(in *JobList, out *expapi.JobList, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*JobList))(in)
|
||||||
|
}
|
||||||
|
if err := convert_v1_TypeMeta_To_api_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := convert_v1_ListMeta_To_api_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if in.Items != nil {
|
||||||
|
out.Items = make([]expapi.Job, len(in.Items))
|
||||||
|
for i := range in.Items {
|
||||||
|
if err := convert_v1_Job_To_expapi_Job(&in.Items[i], &out.Items[i], s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Items = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_v1_JobSpec_To_expapi_JobSpec(in *JobSpec, out *expapi.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 = *in.Parallelism
|
||||||
|
} else {
|
||||||
|
out.Parallelism = nil
|
||||||
|
}
|
||||||
|
if in.Completions != nil {
|
||||||
|
out.Completions = new(int)
|
||||||
|
*out.Completions = *in.Completions
|
||||||
|
} else {
|
||||||
|
out.Completions = nil
|
||||||
|
}
|
||||||
|
if in.Selector != nil {
|
||||||
|
out.Selector = make(map[string]string)
|
||||||
|
for key, val := range in.Selector {
|
||||||
|
out.Selector[key] = val
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Selector = nil
|
||||||
|
}
|
||||||
|
if in.Template != nil {
|
||||||
|
out.Template = new(api.PodTemplateSpec)
|
||||||
|
if err := convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(in.Template, out.Template, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Template = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_v1_JobStatus_To_expapi_JobStatus(in *JobStatus, out *expapi.JobStatus, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*JobStatus))(in)
|
||||||
|
}
|
||||||
|
if in.Conditions != nil {
|
||||||
|
out.Conditions = make([]expapi.JobCondition, len(in.Conditions))
|
||||||
|
for i := range in.Conditions {
|
||||||
|
if err := convert_v1_JobCondition_To_expapi_JobCondition(&in.Conditions[i], &out.Conditions[i], s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Conditions = nil
|
||||||
|
}
|
||||||
|
if in.StartTime != nil {
|
||||||
|
if err := s.Convert(&in.StartTime, &out.StartTime, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.StartTime = nil
|
||||||
|
}
|
||||||
|
if in.CompletionTime != nil {
|
||||||
|
if err := s.Convert(&in.CompletionTime, &out.CompletionTime, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.CompletionTime = nil
|
||||||
|
}
|
||||||
|
out.Active = in.Active
|
||||||
|
out.Successful = in.Successful
|
||||||
|
out.Unsuccessful = in.Unsuccessful
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func convert_v1_ReplicationControllerDummy_To_expapi_ReplicationControllerDummy(in *ReplicationControllerDummy, out *expapi.ReplicationControllerDummy, s conversion.Scope) error {
|
func convert_v1_ReplicationControllerDummy_To_expapi_ReplicationControllerDummy(in *ReplicationControllerDummy, out *expapi.ReplicationControllerDummy, s conversion.Scope) error {
|
||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
defaulting.(func(*ReplicationControllerDummy))(in)
|
defaulting.(func(*ReplicationControllerDummy))(in)
|
||||||
@ -2390,6 +2646,11 @@ func init() {
|
|||||||
convert_expapi_HorizontalPodAutoscalerSpec_To_v1_HorizontalPodAutoscalerSpec,
|
convert_expapi_HorizontalPodAutoscalerSpec_To_v1_HorizontalPodAutoscalerSpec,
|
||||||
convert_expapi_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutoscalerStatus,
|
convert_expapi_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutoscalerStatus,
|
||||||
convert_expapi_HorizontalPodAutoscaler_To_v1_HorizontalPodAutoscaler,
|
convert_expapi_HorizontalPodAutoscaler_To_v1_HorizontalPodAutoscaler,
|
||||||
|
convert_expapi_JobCondition_To_v1_JobCondition,
|
||||||
|
convert_expapi_JobList_To_v1_JobList,
|
||||||
|
convert_expapi_JobSpec_To_v1_JobSpec,
|
||||||
|
convert_expapi_JobStatus_To_v1_JobStatus,
|
||||||
|
convert_expapi_Job_To_v1_Job,
|
||||||
convert_expapi_ReplicationControllerDummy_To_v1_ReplicationControllerDummy,
|
convert_expapi_ReplicationControllerDummy_To_v1_ReplicationControllerDummy,
|
||||||
convert_expapi_ResourceConsumption_To_v1_ResourceConsumption,
|
convert_expapi_ResourceConsumption_To_v1_ResourceConsumption,
|
||||||
convert_expapi_ScaleSpec_To_v1_ScaleSpec,
|
convert_expapi_ScaleSpec_To_v1_ScaleSpec,
|
||||||
@ -2431,6 +2692,11 @@ func init() {
|
|||||||
convert_v1_HorizontalPodAutoscaler_To_expapi_HorizontalPodAutoscaler,
|
convert_v1_HorizontalPodAutoscaler_To_expapi_HorizontalPodAutoscaler,
|
||||||
convert_v1_HostPathVolumeSource_To_api_HostPathVolumeSource,
|
convert_v1_HostPathVolumeSource_To_api_HostPathVolumeSource,
|
||||||
convert_v1_ISCSIVolumeSource_To_api_ISCSIVolumeSource,
|
convert_v1_ISCSIVolumeSource_To_api_ISCSIVolumeSource,
|
||||||
|
convert_v1_JobCondition_To_expapi_JobCondition,
|
||||||
|
convert_v1_JobList_To_expapi_JobList,
|
||||||
|
convert_v1_JobSpec_To_expapi_JobSpec,
|
||||||
|
convert_v1_JobStatus_To_expapi_JobStatus,
|
||||||
|
convert_v1_Job_To_expapi_Job,
|
||||||
convert_v1_Lifecycle_To_api_Lifecycle,
|
convert_v1_Lifecycle_To_api_Lifecycle,
|
||||||
convert_v1_ListMeta_To_api_ListMeta,
|
convert_v1_ListMeta_To_api_ListMeta,
|
||||||
convert_v1_LocalObjectReference_To_api_LocalObjectReference,
|
convert_v1_LocalObjectReference_To_api_LocalObjectReference,
|
||||||
|
@ -998,6 +998,121 @@ func deepCopy_v1_HorizontalPodAutoscalerStatus(in HorizontalPodAutoscalerStatus,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deepCopy_v1_Job(in Job, out *Job, c *conversion.Cloner) error {
|
||||||
|
if err := deepCopy_v1_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deepCopy_v1_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deepCopy_v1_JobSpec(in.Spec, &out.Spec, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deepCopy_v1_JobStatus(in.Status, &out.Status, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopy_v1_JobCondition(in JobCondition, out *JobCondition, c *conversion.Cloner) error {
|
||||||
|
out.Type = in.Type
|
||||||
|
out.Status = in.Status
|
||||||
|
if err := deepCopy_util_Time(in.LastProbeTime, &out.LastProbeTime, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deepCopy_util_Time(in.LastTransitionTime, &out.LastTransitionTime, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out.Reason = in.Reason
|
||||||
|
out.Message = in.Message
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopy_v1_JobList(in JobList, out *JobList, c *conversion.Cloner) error {
|
||||||
|
if err := deepCopy_v1_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deepCopy_v1_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if in.Items != nil {
|
||||||
|
out.Items = make([]Job, len(in.Items))
|
||||||
|
for i := range in.Items {
|
||||||
|
if err := deepCopy_v1_Job(in.Items[i], &out.Items[i], c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Items = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopy_v1_JobSpec(in JobSpec, out *JobSpec, c *conversion.Cloner) error {
|
||||||
|
if in.Parallelism != nil {
|
||||||
|
out.Parallelism = new(int)
|
||||||
|
*out.Parallelism = *in.Parallelism
|
||||||
|
} else {
|
||||||
|
out.Parallelism = nil
|
||||||
|
}
|
||||||
|
if in.Completions != nil {
|
||||||
|
out.Completions = new(int)
|
||||||
|
*out.Completions = *in.Completions
|
||||||
|
} else {
|
||||||
|
out.Completions = nil
|
||||||
|
}
|
||||||
|
if in.Selector != nil {
|
||||||
|
out.Selector = make(map[string]string)
|
||||||
|
for key, val := range in.Selector {
|
||||||
|
out.Selector[key] = val
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Selector = nil
|
||||||
|
}
|
||||||
|
if in.Template != nil {
|
||||||
|
out.Template = new(v1.PodTemplateSpec)
|
||||||
|
if err := deepCopy_v1_PodTemplateSpec(*in.Template, out.Template, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Template = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopy_v1_JobStatus(in JobStatus, out *JobStatus, c *conversion.Cloner) error {
|
||||||
|
if in.Conditions != nil {
|
||||||
|
out.Conditions = make([]JobCondition, len(in.Conditions))
|
||||||
|
for i := range in.Conditions {
|
||||||
|
if err := deepCopy_v1_JobCondition(in.Conditions[i], &out.Conditions[i], c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Conditions = nil
|
||||||
|
}
|
||||||
|
if in.StartTime != nil {
|
||||||
|
out.StartTime = new(util.Time)
|
||||||
|
if err := deepCopy_util_Time(*in.StartTime, out.StartTime, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.StartTime = nil
|
||||||
|
}
|
||||||
|
if in.CompletionTime != nil {
|
||||||
|
out.CompletionTime = new(util.Time)
|
||||||
|
if err := deepCopy_util_Time(*in.CompletionTime, out.CompletionTime, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.CompletionTime = nil
|
||||||
|
}
|
||||||
|
out.Active = in.Active
|
||||||
|
out.Successful = in.Successful
|
||||||
|
out.Unsuccessful = in.Unsuccessful
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func deepCopy_v1_ReplicationControllerDummy(in ReplicationControllerDummy, out *ReplicationControllerDummy, c *conversion.Cloner) error {
|
func deepCopy_v1_ReplicationControllerDummy(in ReplicationControllerDummy, out *ReplicationControllerDummy, c *conversion.Cloner) error {
|
||||||
if err := deepCopy_v1_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
if err := deepCopy_v1_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1228,6 +1343,11 @@ func init() {
|
|||||||
deepCopy_v1_HorizontalPodAutoscalerList,
|
deepCopy_v1_HorizontalPodAutoscalerList,
|
||||||
deepCopy_v1_HorizontalPodAutoscalerSpec,
|
deepCopy_v1_HorizontalPodAutoscalerSpec,
|
||||||
deepCopy_v1_HorizontalPodAutoscalerStatus,
|
deepCopy_v1_HorizontalPodAutoscalerStatus,
|
||||||
|
deepCopy_v1_Job,
|
||||||
|
deepCopy_v1_JobCondition,
|
||||||
|
deepCopy_v1_JobList,
|
||||||
|
deepCopy_v1_JobSpec,
|
||||||
|
deepCopy_v1_JobStatus,
|
||||||
deepCopy_v1_ReplicationControllerDummy,
|
deepCopy_v1_ReplicationControllerDummy,
|
||||||
deepCopy_v1_ResourceConsumption,
|
deepCopy_v1_ResourceConsumption,
|
||||||
deepCopy_v1_RollingUpdateDeployment,
|
deepCopy_v1_RollingUpdateDeployment,
|
||||||
|
@ -36,6 +36,8 @@ func addKnownTypes() {
|
|||||||
&DeploymentList{},
|
&DeploymentList{},
|
||||||
&HorizontalPodAutoscaler{},
|
&HorizontalPodAutoscaler{},
|
||||||
&HorizontalPodAutoscalerList{},
|
&HorizontalPodAutoscalerList{},
|
||||||
|
&Job{},
|
||||||
|
&JobList{},
|
||||||
&ReplicationControllerDummy{},
|
&ReplicationControllerDummy{},
|
||||||
&Scale{},
|
&Scale{},
|
||||||
&ThirdPartyResource{},
|
&ThirdPartyResource{},
|
||||||
@ -51,6 +53,8 @@ func (*Deployment) IsAnAPIObject() {}
|
|||||||
func (*DeploymentList) IsAnAPIObject() {}
|
func (*DeploymentList) IsAnAPIObject() {}
|
||||||
func (*HorizontalPodAutoscaler) IsAnAPIObject() {}
|
func (*HorizontalPodAutoscaler) IsAnAPIObject() {}
|
||||||
func (*HorizontalPodAutoscalerList) IsAnAPIObject() {}
|
func (*HorizontalPodAutoscalerList) IsAnAPIObject() {}
|
||||||
|
func (*Job) IsAnAPIObject() {}
|
||||||
|
func (*JobList) IsAnAPIObject() {}
|
||||||
func (*ReplicationControllerDummy) IsAnAPIObject() {}
|
func (*ReplicationControllerDummy) IsAnAPIObject() {}
|
||||||
func (*Scale) IsAnAPIObject() {}
|
func (*Scale) IsAnAPIObject() {}
|
||||||
func (*ThirdPartyResource) IsAnAPIObject() {}
|
func (*ThirdPartyResource) IsAnAPIObject() {}
|
||||||
|
@ -363,3 +363,102 @@ type ThirdPartyResourceDataList struct {
|
|||||||
// Items is the list of ThirdpartyResourceData.
|
// Items is the list of ThirdpartyResourceData.
|
||||||
Items []ThirdPartyResourceData `json:"items"`
|
Items []ThirdPartyResourceData `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Job represents the configuration of a single job.
|
||||||
|
type Job struct {
|
||||||
|
v1.TypeMeta `json:",inline"`
|
||||||
|
// Standard object's metadata.
|
||||||
|
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
|
||||||
|
v1.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 {
|
||||||
|
v1.TypeMeta `json:",inline"`
|
||||||
|
// Standard list metadata
|
||||||
|
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
|
||||||
|
v1.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. Defaults to 1.
|
||||||
|
Completions *int `json:"completions,omitempty"`
|
||||||
|
|
||||||
|
// Selector is a label query over pods that should match the pod count.
|
||||||
|
Selector map[string]string `json:"selector"`
|
||||||
|
|
||||||
|
// Template is the object that describes the pod that will be created when
|
||||||
|
// executing a job.
|
||||||
|
Template *v1.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 *util.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 *util.Time `json:"completionTime,omitempty"`
|
||||||
|
|
||||||
|
// Active is the number of actively running pods.
|
||||||
|
Active int `json:"active,omitempty"`
|
||||||
|
|
||||||
|
// Successful is the number of pods which reached Phase Succeeded.
|
||||||
|
Successful int `json:"successful,omitempty"`
|
||||||
|
|
||||||
|
// Unsuccessful is the number of pods failures, this applies only to jobs
|
||||||
|
// created with RestartPolicyNever, otherwise this value will always be 0.
|
||||||
|
Unsuccessful int `json:"unsuccessful,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JobConditionType string
|
||||||
|
|
||||||
|
// These are valid conditions of a job.
|
||||||
|
const (
|
||||||
|
// JobComplete means the job has completed its execution.
|
||||||
|
JobComplete JobConditionType = "Complete"
|
||||||
|
)
|
||||||
|
|
||||||
|
// JobCondition describes current state of a job.
|
||||||
|
type JobCondition struct {
|
||||||
|
// Type of job condition, currently only Complete.
|
||||||
|
Type JobConditionType `json:"type"`
|
||||||
|
// Status of the condition, one of True, False, Unknown.
|
||||||
|
Status v1.ConditionStatus `json:"status"`
|
||||||
|
// Last time the condition was checked.
|
||||||
|
LastProbeTime util.Time `json:"lastProbeTime,omitempty"`
|
||||||
|
// Last time the condition transit from one status to another.
|
||||||
|
LastTransitionTime util.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"`
|
||||||
|
}
|
||||||
|
@ -28,6 +28,8 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const isNegativeErrorMsg string = `must be non-negative`
|
||||||
|
|
||||||
// ValidateHorizontalPodAutoscaler can be used to check whether the given autoscaler name is valid.
|
// ValidateHorizontalPodAutoscaler can be used to check whether the given autoscaler name is valid.
|
||||||
// Prefix indicates this name will be used as part of generation, in which case trailing dashes are allowed.
|
// Prefix indicates this name will be used as part of generation, in which case trailing dashes are allowed.
|
||||||
func ValidateHorizontalPodAutoscalerName(name string, prefix bool) (bool, string) {
|
func ValidateHorizontalPodAutoscalerName(name string, prefix bool) (bool, string) {
|
||||||
@ -268,3 +270,50 @@ func ValidateThirdPartyResourceData(obj *expapi.ThirdPartyResourceData) errs.Val
|
|||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ValidateJob(job *expapi.Job) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
// Jobs and rcs have the same name validation
|
||||||
|
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&job.ObjectMeta, true, apivalidation.ValidateReplicationControllerName).Prefix("metadata")...)
|
||||||
|
allErrs = append(allErrs, ValidateJobSpec(&job.Spec).Prefix("spec")...)
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidateJobSpec(spec *expapi.JobSpec) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
|
if spec.Parallelism != nil && *spec.Parallelism < 0 {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("parallelism", spec.Parallelism, isNegativeErrorMsg))
|
||||||
|
}
|
||||||
|
if spec.Completions != nil && *spec.Completions < 0 {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("completions", spec.Completions, isNegativeErrorMsg))
|
||||||
|
}
|
||||||
|
|
||||||
|
selector := labels.Set(spec.Selector).AsSelector()
|
||||||
|
if selector.Empty() {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldRequired("selector"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if spec.Template == nil {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldRequired("template"))
|
||||||
|
} else {
|
||||||
|
labels := labels.Set(spec.Template.Labels)
|
||||||
|
if !selector.Matches(labels) {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("template.labels", spec.Template.Labels, "selector does not match template"))
|
||||||
|
}
|
||||||
|
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(spec.Template).Prefix("template")...)
|
||||||
|
if spec.Template.Spec.RestartPolicy != api.RestartPolicyOnFailure &&
|
||||||
|
spec.Template.Spec.RestartPolicy != api.RestartPolicyNever {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldValueNotSupported("template.spec.restartPolicy",
|
||||||
|
spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidateJobUpdate(oldJob, job *expapi.Job) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta).Prefix("metadata")...)
|
||||||
|
allErrs = append(allErrs, ValidateJobSpec(&job.Spec).Prefix("spec")...)
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
@ -658,3 +658,129 @@ func TestValidateDeployment(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateJob(t *testing.T) {
|
||||||
|
validSelector := map[string]string{"a": "b"}
|
||||||
|
validPodTemplateSpec := api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: validSelector,
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicyOnFailure,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
successCases := []expapi.Job{
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "myjob",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: expapi.JobSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateSpec,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, successCase := range successCases {
|
||||||
|
if errs := ValidateJob(&successCase); len(errs) != 0 {
|
||||||
|
t.Errorf("expected success: %v", errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
negative := -1
|
||||||
|
errorCases := map[string]expapi.Job{
|
||||||
|
"spec.parallelism:must be non-negative": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "myjob",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: expapi.JobSpec{
|
||||||
|
Parallelism: &negative,
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateSpec,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec.completions:must be non-negative": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "myjob",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: expapi.JobSpec{
|
||||||
|
Completions: &negative,
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateSpec,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec.selector:required value": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "myjob",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: expapi.JobSpec{
|
||||||
|
Selector: map[string]string{},
|
||||||
|
Template: &validPodTemplateSpec,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec.template:required value": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "myjob",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: expapi.JobSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec.template.labels:selector does not match template": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "myjob",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: expapi.JobSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
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.spec.restartPolicy:unsupported value": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "myjob",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: expapi.JobSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: validSelector,
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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].(*errors.ValidationError)
|
||||||
|
if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
|
||||||
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -55,6 +55,7 @@ import (
|
|||||||
endpointsetcd "k8s.io/kubernetes/pkg/registry/endpoint/etcd"
|
endpointsetcd "k8s.io/kubernetes/pkg/registry/endpoint/etcd"
|
||||||
eventetcd "k8s.io/kubernetes/pkg/registry/event/etcd"
|
eventetcd "k8s.io/kubernetes/pkg/registry/event/etcd"
|
||||||
expcontrolleretcd "k8s.io/kubernetes/pkg/registry/experimental/controller/etcd"
|
expcontrolleretcd "k8s.io/kubernetes/pkg/registry/experimental/controller/etcd"
|
||||||
|
jobetcd "k8s.io/kubernetes/pkg/registry/job/etcd"
|
||||||
limitrangeetcd "k8s.io/kubernetes/pkg/registry/limitrange/etcd"
|
limitrangeetcd "k8s.io/kubernetes/pkg/registry/limitrange/etcd"
|
||||||
"k8s.io/kubernetes/pkg/registry/namespace"
|
"k8s.io/kubernetes/pkg/registry/namespace"
|
||||||
namespaceetcd "k8s.io/kubernetes/pkg/registry/namespace/etcd"
|
namespaceetcd "k8s.io/kubernetes/pkg/registry/namespace/etcd"
|
||||||
@ -827,6 +828,7 @@ func (m *Master) expapi(c *Config) *apiserver.APIGroupVersion {
|
|||||||
thirdPartyResourceStorage := thirdpartyresourceetcd.NewREST(c.ExpDatabaseStorage)
|
thirdPartyResourceStorage := thirdpartyresourceetcd.NewREST(c.ExpDatabaseStorage)
|
||||||
daemonSetStorage := daemonetcd.NewREST(c.ExpDatabaseStorage)
|
daemonSetStorage := daemonetcd.NewREST(c.ExpDatabaseStorage)
|
||||||
deploymentStorage := deploymentetcd.NewREST(c.ExpDatabaseStorage)
|
deploymentStorage := deploymentetcd.NewREST(c.ExpDatabaseStorage)
|
||||||
|
jobStorage := jobetcd.NewREST(c.ExpDatabaseStorage)
|
||||||
|
|
||||||
storage := map[string]rest.Storage{
|
storage := map[string]rest.Storage{
|
||||||
strings.ToLower("replicationControllers"): controllerStorage.ReplicationController,
|
strings.ToLower("replicationControllers"): controllerStorage.ReplicationController,
|
||||||
@ -835,6 +837,7 @@ func (m *Master) expapi(c *Config) *apiserver.APIGroupVersion {
|
|||||||
strings.ToLower("thirdpartyresources"): thirdPartyResourceStorage,
|
strings.ToLower("thirdpartyresources"): thirdPartyResourceStorage,
|
||||||
strings.ToLower("daemonsets"): daemonSetStorage,
|
strings.ToLower("daemonsets"): daemonSetStorage,
|
||||||
strings.ToLower("deployments"): deploymentStorage,
|
strings.ToLower("deployments"): deploymentStorage,
|
||||||
|
strings.ToLower("jobs"): jobStorage,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &apiserver.APIGroupVersion{
|
return &apiserver.APIGroupVersion{
|
||||||
|
19
pkg/registry/job/doc.go
Normal file
19
pkg/registry/job/doc.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package controller provides Registry interface and it's RESTStorage
|
||||||
|
// implementation for storing Job api objects.
|
||||||
|
package job
|
77
pkg/registry/job/etcd/etcd.go
Normal file
77
pkg/registry/job/etcd/etcd.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package etcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
|
etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd"
|
||||||
|
"k8s.io/kubernetes/pkg/registry/job"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
// rest implements a RESTStorage for jobs against etcd
|
||||||
|
type REST struct {
|
||||||
|
*etcdgeneric.Etcd
|
||||||
|
}
|
||||||
|
|
||||||
|
// jobPrefix is the location for jobs in etcd, only exposed
|
||||||
|
// for testing
|
||||||
|
var jobPrefix = "/jobs"
|
||||||
|
|
||||||
|
// NewREST returns a RESTStorage object that will work against Jobs.
|
||||||
|
func NewREST(s storage.Interface) *REST {
|
||||||
|
store := &etcdgeneric.Etcd{
|
||||||
|
NewFunc: func() runtime.Object { return &expapi.Job{} },
|
||||||
|
|
||||||
|
// NewListFunc returns an object capable of storing results of an etcd list.
|
||||||
|
NewListFunc: func() runtime.Object { return &expapi.JobList{} },
|
||||||
|
// Produces a path that etcd understands, to the root of the resource
|
||||||
|
// by combining the namespace in the context with the given prefix
|
||||||
|
KeyRootFunc: func(ctx api.Context) string {
|
||||||
|
return etcdgeneric.NamespaceKeyRootFunc(ctx, jobPrefix)
|
||||||
|
},
|
||||||
|
// Produces a path that etcd understands, to the resource by combining
|
||||||
|
// the namespace in the context with the given prefix
|
||||||
|
KeyFunc: func(ctx api.Context, name string) (string, error) {
|
||||||
|
return etcdgeneric.NamespaceKeyFunc(ctx, jobPrefix, name)
|
||||||
|
},
|
||||||
|
// Retrieve the name field of a job
|
||||||
|
ObjectNameFunc: func(obj runtime.Object) (string, error) {
|
||||||
|
return obj.(*expapi.Job).Name, nil
|
||||||
|
},
|
||||||
|
// Used to match objects based on labels/fields for list and watch
|
||||||
|
PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||||
|
return job.MatchJob(label, field)
|
||||||
|
},
|
||||||
|
EndpointName: "jobs",
|
||||||
|
|
||||||
|
// Used to validate job creation
|
||||||
|
CreateStrategy: job.Strategy,
|
||||||
|
|
||||||
|
// Used to validate job updates
|
||||||
|
UpdateStrategy: job.Strategy,
|
||||||
|
|
||||||
|
Storage: s,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &REST{store}
|
||||||
|
}
|
148
pkg/registry/job/etcd/etcd_test.go
Normal file
148
pkg/registry/job/etcd/etcd_test.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package etcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
// Ensure that expapi/v1 package is initialized.
|
||||||
|
_ "k8s.io/kubernetes/pkg/expapi/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/tools"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
|
||||||
|
etcdStorage, fakeClient := registrytest.NewEtcdStorage(t, "experimental")
|
||||||
|
return NewREST(etcdStorage), fakeClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func validNewJob() *expapi.Job {
|
||||||
|
completions := 1
|
||||||
|
parallelism := 1
|
||||||
|
return &expapi.Job{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
Spec: expapi.JobSpec{
|
||||||
|
Completions: &completions,
|
||||||
|
Parallelism: ¶llelism,
|
||||||
|
Selector: map[string]string{"a": "b"},
|
||||||
|
Template: &api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: map[string]string{"a": "b"},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "test",
|
||||||
|
Image: "test_image",
|
||||||
|
ImagePullPolicy: api.PullIfNotPresent,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RestartPolicy: api.RestartPolicyOnFailure,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreate(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
validJob := validNewJob()
|
||||||
|
validJob.ObjectMeta = api.ObjectMeta{}
|
||||||
|
test.TestCreate(
|
||||||
|
// valid
|
||||||
|
validJob,
|
||||||
|
// invalid (empty selector)
|
||||||
|
&expapi.Job{
|
||||||
|
Spec: expapi.JobSpec{
|
||||||
|
Completions: validJob.Spec.Completions,
|
||||||
|
Selector: map[string]string{},
|
||||||
|
Template: validJob.Spec.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdate(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
completions := 2
|
||||||
|
test.TestUpdate(
|
||||||
|
// valid
|
||||||
|
validNewJob(),
|
||||||
|
// updateFunc
|
||||||
|
func(obj runtime.Object) runtime.Object {
|
||||||
|
object := obj.(*expapi.Job)
|
||||||
|
object.Spec.Completions = &completions
|
||||||
|
return object
|
||||||
|
},
|
||||||
|
// invalid updateFunc
|
||||||
|
func(obj runtime.Object) runtime.Object {
|
||||||
|
object := obj.(*expapi.Job)
|
||||||
|
object.Spec.Selector = map[string]string{}
|
||||||
|
return object
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
test.TestDelete(validNewJob())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
test.TestGet(validNewJob())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestList(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
test.TestList(validNewJob())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWatch(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
test.TestWatch(
|
||||||
|
validNewJob(),
|
||||||
|
// matching labels
|
||||||
|
[]labels.Set{},
|
||||||
|
// not matching labels
|
||||||
|
[]labels.Set{
|
||||||
|
{"x": "y"},
|
||||||
|
},
|
||||||
|
// matching fields
|
||||||
|
[]fields.Set{},
|
||||||
|
// not matching fields
|
||||||
|
[]fields.Set{
|
||||||
|
{"metadata.name": "xyz"},
|
||||||
|
{"name": "foo"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
99
pkg/registry/job/registry.go
Normal file
99
pkg/registry/job/registry.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package job
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Registry is an interface for things that know how to store Jobs.
|
||||||
|
type Registry interface {
|
||||||
|
// ListJobs obtains a list of Jobs having labels and fields which match selector.
|
||||||
|
ListJobs(ctx api.Context, label labels.Selector, field fields.Selector) (*expapi.JobList, error)
|
||||||
|
// WatchJobs watch for new/changed/deleted Jobs.
|
||||||
|
WatchJobs(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
|
||||||
|
// GetJobs gets a specific Job.
|
||||||
|
GetJob(ctx api.Context, name string) (*expapi.Job, error)
|
||||||
|
// CreateJob creates a Job based on a specification.
|
||||||
|
CreateJob(ctx api.Context, job *expapi.Job) (*expapi.Job, error)
|
||||||
|
// UpdateJob updates an existing Job.
|
||||||
|
UpdateJob(ctx api.Context, job *expapi.Job) (*expapi.Job, error)
|
||||||
|
// DeleteJob deletes an existing Job.
|
||||||
|
DeleteJob(ctx api.Context, name string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// storage puts strong typing around storage calls
|
||||||
|
type storage struct {
|
||||||
|
rest.StandardStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRegistry returns a new Registry interface for the given Storage. Any mismatched
|
||||||
|
// types will panic.
|
||||||
|
func NewRegistry(s rest.StandardStorage) Registry {
|
||||||
|
return &storage{s}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) ListJobs(ctx api.Context, label labels.Selector, field fields.Selector) (*expapi.JobList, error) {
|
||||||
|
if !field.Empty() {
|
||||||
|
return nil, fmt.Errorf("field selector not supported yet")
|
||||||
|
}
|
||||||
|
obj, err := s.List(ctx, label, field)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*expapi.JobList), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) WatchJobs(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
|
||||||
|
return s.Watch(ctx, label, field, resourceVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) GetJob(ctx api.Context, name string) (*expapi.Job, error) {
|
||||||
|
obj, err := s.Get(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*expapi.Job), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) CreateJob(ctx api.Context, job *expapi.Job) (*expapi.Job, error) {
|
||||||
|
obj, err := s.Create(ctx, job)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*expapi.Job), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) UpdateJob(ctx api.Context, job *expapi.Job) (*expapi.Job, error) {
|
||||||
|
obj, _, err := s.Update(ctx, job)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*expapi.Job), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *storage) DeleteJob(ctx api.Context, name string) error {
|
||||||
|
_, err := s.Delete(ctx, name, nil)
|
||||||
|
return err
|
||||||
|
}
|
105
pkg/registry/job/strategy.go
Normal file
105
pkg/registry/job/strategy.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package job
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi/validation"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/util/fielderrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// jobStrategy implements verification logic for Replication Controllers.
|
||||||
|
type jobStrategy struct {
|
||||||
|
runtime.ObjectTyper
|
||||||
|
api.NameGenerator
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy is the default logic that applies when creating and updating Replication Controller objects.
|
||||||
|
var Strategy = jobStrategy{api.Scheme, api.SimpleNameGenerator}
|
||||||
|
|
||||||
|
// NamespaceScoped returns true because all jobs need to be within a namespace.
|
||||||
|
func (jobStrategy) NamespaceScoped() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareForCreate clears the status of a job before creation.
|
||||||
|
func (jobStrategy) PrepareForCreate(obj runtime.Object) {
|
||||||
|
job := obj.(*expapi.Job)
|
||||||
|
job.Status = expapi.JobStatus{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||||
|
func (jobStrategy) PrepareForUpdate(obj, old runtime.Object) {
|
||||||
|
newJob := obj.(*expapi.Job)
|
||||||
|
oldJob := old.(*expapi.Job)
|
||||||
|
newJob.Status = oldJob.Status
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates a new job.
|
||||||
|
func (jobStrategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList {
|
||||||
|
job := obj.(*expapi.Job)
|
||||||
|
return validation.ValidateJob(job)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jobStrategy) AllowUnconditionalUpdate() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowCreateOnUpdate is false for jobs; this means a POST is needed to create one.
|
||||||
|
func (jobStrategy) AllowCreateOnUpdate() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateUpdate is the default update validation for an end user.
|
||||||
|
func (jobStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) fielderrors.ValidationErrorList {
|
||||||
|
validationErrorList := validation.ValidateJob(obj.(*expapi.Job))
|
||||||
|
updateErrorList := validation.ValidateJobUpdate(old.(*expapi.Job), obj.(*expapi.Job))
|
||||||
|
return append(validationErrorList, updateErrorList...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// JobSelectableFields returns a field set that represents the object for matching purposes.
|
||||||
|
func JobToSelectableFields(job *expapi.Job) fields.Set {
|
||||||
|
return fields.Set{
|
||||||
|
"metadata.name": job.Name,
|
||||||
|
"status.successful": strconv.Itoa(job.Status.Successful),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchJob is the filter used by the generic etcd backend to route
|
||||||
|
// watch events from etcd to clients of the apiserver only interested in specific
|
||||||
|
// labels/fields.
|
||||||
|
func MatchJob(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||||
|
return &generic.SelectionPredicate{
|
||||||
|
Label: label,
|
||||||
|
Field: field,
|
||||||
|
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||||
|
job, ok := obj.(*expapi.Job)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, fmt.Errorf("Given object is not a job.")
|
||||||
|
}
|
||||||
|
return labels.Set(job.ObjectMeta.Labels), JobToSelectableFields(job), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user