diff --git a/pkg/apis/batch/validation/validation.go b/pkg/apis/batch/validation/validation.go index 5a97095d261..61b59523864 100644 --- a/pkg/apis/batch/validation/validation.go +++ b/pkg/apis/batch/validation/validation.go @@ -263,6 +263,8 @@ func validatePodTemplateUpdate(spec, oldSpec batch.JobSpec, fldPath *field.Path, } oldTemplate.Spec.NodeSelector = template.Spec.NodeSelector // +k8s:verify-mutation:reason=clone oldTemplate.Spec.Tolerations = template.Spec.Tolerations // +k8s:verify-mutation:reason=clone + oldTemplate.Annotations = template.Annotations // +k8s:verify-mutation:reason=clone + oldTemplate.Labels = template.Labels // +k8s:verify-mutation:reason=clone } allErrs = append(allErrs, apivalidation.ValidateImmutableField(template, oldTemplate, fldPath.Child("template"))...) return allErrs diff --git a/pkg/apis/batch/validation/validation_test.go b/pkg/apis/batch/validation/validation_test.go index ec0e4d01bbd..b33bdff409b 100644 --- a/pkg/apis/batch/validation/validation_test.go +++ b/pkg/apis/batch/validation/validation_test.go @@ -647,6 +647,72 @@ func TestValidateJobUpdate(t *testing.T) { AllowMutableSchedulingDirectives: true, }, }, + "immutable annotations": { + old: batch.Job{ + ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, + Spec: batch.JobSpec{ + Selector: validGeneratedSelector, + Template: validPodTemplateSpecForGenerated, + }, + }, + update: func(job *batch.Job) { + job.Spec.Template.Annotations = map[string]string{"foo": "baz"} + }, + err: &field.Error{ + Type: field.ErrorTypeInvalid, + Field: "spec.template", + }, + }, + "mutable annotations": { + old: batch.Job{ + ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, + Spec: batch.JobSpec{ + Selector: validGeneratedSelector, + Template: validPodTemplateSpecForGenerated, + }, + }, + update: func(job *batch.Job) { + job.Spec.Template.Annotations = map[string]string{"foo": "baz"} + }, + opts: JobValidationOptions{ + AllowMutableSchedulingDirectives: true, + }, + }, + "immutable labels": { + old: batch.Job{ + ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, + Spec: batch.JobSpec{ + Selector: validGeneratedSelector, + Template: validPodTemplateSpecForGenerated, + }, + }, + update: func(job *batch.Job) { + newLabels := getValidGeneratedSelector().MatchLabels + newLabels["bar"] = "baz" + job.Spec.Template.Labels = newLabels + }, + err: &field.Error{ + Type: field.ErrorTypeInvalid, + Field: "spec.template", + }, + }, + "mutable labels": { + old: batch.Job{ + ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, + Spec: batch.JobSpec{ + Selector: validGeneratedSelector, + Template: validPodTemplateSpecForGenerated, + }, + }, + update: func(job *batch.Job) { + newLabels := getValidGeneratedSelector().MatchLabels + newLabels["bar"] = "baz" + job.Spec.Template.Labels = newLabels + }, + opts: JobValidationOptions{ + AllowMutableSchedulingDirectives: true, + }, + }, } ignoreValueAndDetail := cmpopts.IgnoreFields(field.Error{}, "BadValue", "Detail") for k, tc := range cases {