Add Job.spec.completionMode and Job.status.completedIndexes

And IndexedJob feature gate, disabled by default.
Update JobDescriber
This commit is contained in:
Aldo Culquicondor
2020-12-30 11:42:01 -05:00
parent 6404eda8de
commit a1a5868a5a
36 changed files with 642 additions and 157 deletions

View File

@@ -78,7 +78,7 @@ func TestValidateJob(t *testing.T) {
validPodTemplateSpecForGenerated := getValidPodTemplateSpecForGenerated(validGeneratedSelector)
successCases := map[string]batch.Job{
"manual selector": {
"valid manual selector": {
ObjectMeta: metav1.ObjectMeta{
Name: "myjob",
Namespace: metav1.NamespaceDefault,
@@ -90,7 +90,7 @@ func TestValidateJob(t *testing.T) {
Template: validPodTemplateSpecForManual,
},
},
"generated selector": {
"valid generated selector": {
ObjectMeta: metav1.ObjectMeta{
Name: "myjob",
Namespace: metav1.NamespaceDefault,
@@ -101,6 +101,32 @@ func TestValidateJob(t *testing.T) {
Template: validPodTemplateSpecForGenerated,
},
},
"valid NonIndexed completion mode": {
ObjectMeta: metav1.ObjectMeta{
Name: "myjob",
Namespace: metav1.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGenerated,
CompletionMode: batch.NonIndexedCompletion,
},
},
"valid Indexed completion mode": {
ObjectMeta: metav1.ObjectMeta{
Name: "myjob",
Namespace: metav1.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGenerated,
CompletionMode: batch.IndexedCompletion,
Completions: pointer.Int32Ptr(2),
Parallelism: pointer.Int32Ptr(100000),
},
},
}
for k, v := range successCases {
t.Run(k, func(t *testing.T) {
@@ -158,7 +184,7 @@ func TestValidateJob(t *testing.T) {
Template: validPodTemplateSpecForGenerated,
},
},
"spec.template.metadata.labels: Invalid value: {\"y\":\"z\"}: `selector` does not match template `labels`": {
"spec.template.metadata.labels: Invalid value: map[string]string{\"y\":\"z\"}: `selector` does not match template `labels`": {
ObjectMeta: metav1.ObjectMeta{
Name: "myjob",
Namespace: metav1.NamespaceDefault,
@@ -179,7 +205,7 @@ func TestValidateJob(t *testing.T) {
},
},
},
"spec.template.metadata.labels: Invalid value: {\"controller-uid\":\"4d5e6f\"}: `selector` does not match template `labels`": {
"spec.template.metadata.labels: Invalid value: map[string]string{\"controller-uid\":\"4d5e6f\"}: `selector` does not match template `labels`": {
ObjectMeta: metav1.ObjectMeta{
Name: "myjob",
Namespace: metav1.NamespaceDefault,
@@ -242,7 +268,7 @@ func TestValidateJob(t *testing.T) {
},
},
},
"spec.ttlSecondsAfterFinished:must be greater than or equal to 0": {
"spec.ttlSecondsAfterFinished: must be greater than or equal to 0": {
ObjectMeta: metav1.ObjectMeta{
Name: "myjob",
Namespace: metav1.NamespaceDefault,
@@ -254,6 +280,32 @@ func TestValidateJob(t *testing.T) {
Template: validPodTemplateSpecForGenerated,
},
},
"spec.completions: Required value: when completion mode is Indexed": {
ObjectMeta: metav1.ObjectMeta{
Name: "myjob",
Namespace: metav1.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGenerated,
CompletionMode: batch.IndexedCompletion,
},
},
"spec.parallelism: must be less than or equal to 100000 when completion mode is Indexed": {
ObjectMeta: metav1.ObjectMeta{
Name: "myjob",
Namespace: metav1.NamespaceDefault,
UID: types.UID("1a2b3c"),
},
Spec: batch.JobSpec{
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGenerated,
CompletionMode: batch.IndexedCompletion,
Completions: pointer.Int32Ptr(2),
Parallelism: pointer.Int32Ptr(100001),
},
},
}
for k, v := range errorCases {
@@ -262,7 +314,7 @@ func TestValidateJob(t *testing.T) {
if len(errs) == 0 {
t.Errorf("expected failure for %s", k)
} else {
s := strings.Split(k, ":")
s := strings.SplitN(k, ":", 2)
err := errs[0]
if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
t.Errorf("unexpected error: %v, expected: %s", err, k)
@@ -346,6 +398,24 @@ func TestValidateJobUpdate(t *testing.T) {
Field: "spec.template",
},
},
"immutable completion mode": {
old: batch.Job{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: batch.JobSpec{
Selector: validGeneratedSelector,
Template: validPodTemplateSpecForGenerated,
CompletionMode: batch.IndexedCompletion,
Completions: pointer.Int32Ptr(2),
},
},
update: func(job *batch.Job) {
job.Spec.CompletionMode = batch.NonIndexedCompletion
},
err: &field.Error{
Type: field.ErrorTypeInvalid,
Field: "spec.completionMode",
},
},
}
ignoreValueAndDetail := cmpopts.IgnoreFields(field.Error{}, "BadValue", "Detail")
for k, tc := range cases {