Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
e55c59e8
Commit
e55c59e8
authored
Aug 18, 2015
by
Maciej Szulik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New Job resource
parent
90ba96d4
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1338 additions
and
0 deletions
+1338
-0
deep_copy_generated.go
pkg/expapi/deep_copy_generated.go
+120
-0
register.go
pkg/expapi/register.go
+4
-0
types.go
pkg/expapi/types.go
+99
-0
conversion_generated.go
pkg/expapi/v1/conversion_generated.go
+266
-0
deep_copy_generated.go
pkg/expapi/v1/deep_copy_generated.go
+120
-0
register.go
pkg/expapi/v1/register.go
+4
-0
types.go
pkg/expapi/v1/types.go
+99
-0
validation.go
pkg/expapi/validation/validation.go
+49
-0
validation_test.go
pkg/expapi/validation/validation_test.go
+126
-0
master.go
pkg/master/master.go
+3
-0
doc.go
pkg/registry/job/doc.go
+19
-0
etcd.go
pkg/registry/job/etcd/etcd.go
+77
-0
etcd_test.go
pkg/registry/job/etcd/etcd_test.go
+148
-0
registry.go
pkg/registry/job/registry.go
+99
-0
strategy.go
pkg/registry/job/strategy.go
+105
-0
No files found.
pkg/expapi/deep_copy_generated.go
View file @
e55c59e8
...
...
@@ -986,6 +986,121 @@ func deepCopy_expapi_HorizontalPodAutoscalerStatus(in HorizontalPodAutoscalerSta
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
{
if
err
:=
deepCopy_api_TypeMeta
(
in
.
TypeMeta
,
&
out
.
TypeMeta
,
c
);
err
!=
nil
{
return
err
...
...
@@ -1206,6 +1321,11 @@ func init() {
deepCopy_expapi_HorizontalPodAutoscalerList
,
deepCopy_expapi_HorizontalPodAutoscalerSpec
,
deepCopy_expapi_HorizontalPodAutoscalerStatus
,
deepCopy_expapi_Job
,
deepCopy_expapi_JobCondition
,
deepCopy_expapi_JobList
,
deepCopy_expapi_JobSpec
,
deepCopy_expapi_JobStatus
,
deepCopy_expapi_ReplicationControllerDummy
,
deepCopy_expapi_ResourceConsumption
,
deepCopy_expapi_RollingUpdateDeployment
,
...
...
pkg/expapi/register.go
View file @
e55c59e8
...
...
@@ -32,6 +32,8 @@ func addKnownTypes() {
&
DeploymentList
{},
&
HorizontalPodAutoscaler
{},
&
HorizontalPodAutoscalerList
{},
&
Job
{},
&
JobList
{},
&
ReplicationControllerDummy
{},
&
Scale
{},
&
ThirdPartyResource
{},
...
...
@@ -47,6 +49,8 @@ func (*Deployment) IsAnAPIObject() {}
func
(
*
DeploymentList
)
IsAnAPIObject
()
{}
func
(
*
HorizontalPodAutoscaler
)
IsAnAPIObject
()
{}
func
(
*
HorizontalPodAutoscalerList
)
IsAnAPIObject
()
{}
func
(
*
Job
)
IsAnAPIObject
()
{}
func
(
*
JobList
)
IsAnAPIObject
()
{}
func
(
*
ReplicationControllerDummy
)
IsAnAPIObject
()
{}
func
(
*
Scale
)
IsAnAPIObject
()
{}
func
(
*
ThirdPartyResource
)
IsAnAPIObject
()
{}
...
...
pkg/expapi/types.go
View file @
e55c59e8
...
...
@@ -362,3 +362,102 @@ type ThirdPartyResourceDataList struct {
// Items is a list of third party objects
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"`
}
pkg/expapi/v1/conversion_generated.go
View file @
e55c59e8
...
...
@@ -1788,6 +1788,134 @@ func convert_expapi_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutoscalerS
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
{
if
defaulting
,
found
:=
s
.
DefaultingInterface
(
reflect
.
TypeOf
(
*
in
));
found
{
defaulting
.
(
func
(
*
expapi
.
ReplicationControllerDummy
))(
in
)
...
...
@@ -2176,6 +2304,134 @@ func convert_v1_HorizontalPodAutoscalerStatus_To_expapi_HorizontalPodAutoscalerS
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
{
if
defaulting
,
found
:=
s
.
DefaultingInterface
(
reflect
.
TypeOf
(
*
in
));
found
{
defaulting
.
(
func
(
*
ReplicationControllerDummy
))(
in
)
...
...
@@ -2390,6 +2646,11 @@ func init() {
convert_expapi_HorizontalPodAutoscalerSpec_To_v1_HorizontalPodAutoscalerSpec
,
convert_expapi_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutoscalerStatus
,
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_ResourceConsumption_To_v1_ResourceConsumption
,
convert_expapi_ScaleSpec_To_v1_ScaleSpec
,
...
...
@@ -2431,6 +2692,11 @@ func init() {
convert_v1_HorizontalPodAutoscaler_To_expapi_HorizontalPodAutoscaler
,
convert_v1_HostPathVolumeSource_To_api_HostPathVolumeSource
,
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_ListMeta_To_api_ListMeta
,
convert_v1_LocalObjectReference_To_api_LocalObjectReference
,
...
...
pkg/expapi/v1/deep_copy_generated.go
View file @
e55c59e8
...
...
@@ -998,6 +998,121 @@ func deepCopy_v1_HorizontalPodAutoscalerStatus(in HorizontalPodAutoscalerStatus,
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
{
if
err
:=
deepCopy_v1_TypeMeta
(
in
.
TypeMeta
,
&
out
.
TypeMeta
,
c
);
err
!=
nil
{
return
err
...
...
@@ -1228,6 +1343,11 @@ func init() {
deepCopy_v1_HorizontalPodAutoscalerList
,
deepCopy_v1_HorizontalPodAutoscalerSpec
,
deepCopy_v1_HorizontalPodAutoscalerStatus
,
deepCopy_v1_Job
,
deepCopy_v1_JobCondition
,
deepCopy_v1_JobList
,
deepCopy_v1_JobSpec
,
deepCopy_v1_JobStatus
,
deepCopy_v1_ReplicationControllerDummy
,
deepCopy_v1_ResourceConsumption
,
deepCopy_v1_RollingUpdateDeployment
,
...
...
pkg/expapi/v1/register.go
View file @
e55c59e8
...
...
@@ -36,6 +36,8 @@ func addKnownTypes() {
&
DeploymentList
{},
&
HorizontalPodAutoscaler
{},
&
HorizontalPodAutoscalerList
{},
&
Job
{},
&
JobList
{},
&
ReplicationControllerDummy
{},
&
Scale
{},
&
ThirdPartyResource
{},
...
...
@@ -51,6 +53,8 @@ func (*Deployment) IsAnAPIObject() {}
func
(
*
DeploymentList
)
IsAnAPIObject
()
{}
func
(
*
HorizontalPodAutoscaler
)
IsAnAPIObject
()
{}
func
(
*
HorizontalPodAutoscalerList
)
IsAnAPIObject
()
{}
func
(
*
Job
)
IsAnAPIObject
()
{}
func
(
*
JobList
)
IsAnAPIObject
()
{}
func
(
*
ReplicationControllerDummy
)
IsAnAPIObject
()
{}
func
(
*
Scale
)
IsAnAPIObject
()
{}
func
(
*
ThirdPartyResource
)
IsAnAPIObject
()
{}
...
...
pkg/expapi/v1/types.go
View file @
e55c59e8
...
...
@@ -363,3 +363,102 @@ type ThirdPartyResourceDataList struct {
// Items is the list of ThirdpartyResourceData.
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"`
}
pkg/expapi/validation/validation.go
View file @
e55c59e8
...
...
@@ -28,6 +28,8 @@ import (
"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.
// 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
)
{
...
...
@@ -268,3 +270,50 @@ func ValidateThirdPartyResourceData(obj *expapi.ThirdPartyResourceData) errs.Val
}
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
}
pkg/expapi/validation/validation_test.go
View file @
e55c59e8
...
...
@@ -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
)
}
}
}
}
pkg/master/master.go
View file @
e55c59e8
...
...
@@ -55,6 +55,7 @@ import (
endpointsetcd
"k8s.io/kubernetes/pkg/registry/endpoint/etcd"
eventetcd
"k8s.io/kubernetes/pkg/registry/event/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"
"k8s.io/kubernetes/pkg/registry/namespace"
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
)
daemonSetStorage
:=
daemonetcd
.
NewREST
(
c
.
ExpDatabaseStorage
)
deploymentStorage
:=
deploymentetcd
.
NewREST
(
c
.
ExpDatabaseStorage
)
jobStorage
:=
jobetcd
.
NewREST
(
c
.
ExpDatabaseStorage
)
storage
:=
map
[
string
]
rest
.
Storage
{
strings
.
ToLower
(
"replicationControllers"
)
:
controllerStorage
.
ReplicationController
,
...
...
@@ -835,6 +837,7 @@ func (m *Master) expapi(c *Config) *apiserver.APIGroupVersion {
strings
.
ToLower
(
"thirdpartyresources"
)
:
thirdPartyResourceStorage
,
strings
.
ToLower
(
"daemonsets"
)
:
daemonSetStorage
,
strings
.
ToLower
(
"deployments"
)
:
deploymentStorage
,
strings
.
ToLower
(
"jobs"
)
:
jobStorage
,
}
return
&
apiserver
.
APIGroupVersion
{
...
...
pkg/registry/job/doc.go
0 → 100644
View file @
e55c59e8
/*
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
pkg/registry/job/etcd/etcd.go
0 → 100644
View file @
e55c59e8
/*
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
}
}
pkg/registry/job/etcd/etcd_test.go
0 → 100644
View file @
e55c59e8
/*
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
:
&
parallelism
,
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"
},
},
)
}
pkg/registry/job/registry.go
0 → 100644
View file @
e55c59e8
/*
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
}
pkg/registry/job/strategy.go
0 → 100644
View file @
e55c59e8
/*
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
},
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment