Repository: kubernetes/kubernetes
File: pkg/registry/batch/job/strategy.go (Go)

Code before:
	job := obj.(*batch.Job)
	opts := validationOptionsForJob(job, nil)
	return batchvalidation.ValidateJob(job, opts)
}

func validationOptionsForJob(newJob, oldJob *batch.Job) batchvalidation.JobValidationOptions {
	var newPodTemplate, oldPodTemplate *core.PodTemplateSpec
	if newJob != nil {
		newPodTemplate = &newJob.Spec.Template
	}
	if oldJob != nil {
		oldPodTemplate = &oldJob.Spec.Template
	}
	opts := batchvalidation.JobValidationOptions{
		PodValidationOptions:  pod.GetValidationOptionsFromPodTemplate(newPodTemplate, oldPodTemplate),
		RequirePrefixedLabels: true,
	}
	if oldJob != nil {
		opts.AllowInvalidLabelValueInSelector = opts.AllowInvalidLabelValueInSelector || metav1validation.LabelSelectorHasInvalidLabelValue(oldJob.Spec.Selector)
		// Updating node affinity, node selector and tolerations is allowed
		// only for suspended jobs that never started before.
		suspended := oldJob.Spec.Suspend != nil && *oldJob.Spec.Suspend
		notStarted := oldJob.Status.StartTime == nil
		opts.AllowMutableSchedulingDirectives = suspended && notStarted
		if utilfeature.DefaultFeatureGate.Enabled(features.MutablePodResourcesForSuspendedJobs) {
			opts.AllowMutablePodResources = batchvalidation.IsConditionTrue(oldJob.Status.Conditions, batch.JobSuspended) && oldJob.Status.Active == 0
		}
		if utilfeature.DefaultFeatureGate.Enabled(features.MutableSchedulingDirectivesForSuspendedJobs) {
			opts.AllowMutableSchedulingDirectives = suspended && batchvalidation.IsConditionTrue(oldJob.Status.Conditions, batch.JobSuspended) && oldJob.Status.Active == 0
		}
		// Validation should not fail jobs if they don't have the new labels.
		// This can be removed once we have high confidence that both labels exist (1.30 at least)
		_, hadJobName := oldJob.Spec.Template.Labels[batch.JobNameLabel]
		_, hadControllerUid := oldJob.Spec.Template.Labels[batch.ControllerUidLabel]
		opts.RequirePrefixedLabels = hadJobName && hadControllerUid
	}
	return opts
}

// WarningsOnCreate returns warnings for the creation of the given object.
func (jobStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
	newJob := obj.(*batch.Job)
	var warnings []string
	if msgs := utilvalidation.IsDNS1123Label(newJob.Name); len(msgs) != 0 {
		warnings = append(warnings, fmt.Sprintf("metadata.name: this is used in Pod names and hostnames, which can result in surprising behavior; a DNS label is recommended: %v", msgs))
	}
	warnings = append(warnings, job.WarningsForJobSpec(ctx, field.NewPath("spec"), &newJob.Spec, nil)...)
	return warnings
}

// generateSelectorIfNeeded checks the job's manual selector flag and generates selector labels if the flag is true.

Review comment (bug):
Actually, I have tested this is not a bug - the test passes also on the master branch, because of this "if": https://github.com/kubernetes/kubernetes/blob/9f6977db54084d766c1fec19f383bf509d7e8610/pkg/apis/batch/validation/validation.go#L663-L666

So, I think we can just call the PR cleanup, and orient on adding the tests. I'm ok to either include this check, or revert. This is just short-circuit now.

Code after:
	job := obj.(*batch.Job)
	opts := validationOptionsForJob(job, nil)
	return batchvalidation.ValidateJob(job, opts)
}

func validationOptionsForJob(newJob, oldJob *batch.Job) batchvalidation.JobValidationOptions {
	var newPodTemplate, oldPodTemplate *core.PodTemplateSpec
	if newJob != nil {
		newPodTemplate = &newJob.Spec.Template
	}
	if oldJob != nil {
		oldPodTemplate = &oldJob.Spec.Template
	}
	opts := batchvalidation.JobValidationOptions{
		PodValidationOptions:  pod.GetValidationOptionsFromPodTemplate(newPodTemplate, oldPodTemplate),
		RequirePrefixedLabels: true,
	}
	if oldJob != nil {
		opts.AllowInvalidLabelValueInSelector = opts.AllowInvalidLabelValueInSelector || metav1validation.LabelSelectorHasInvalidLabelValue(oldJob.Spec.Selector)
		// Updating node affinity, node selector and tolerations is allowed
		// only for suspended jobs that never started before.
		suspended := oldJob.Spec.Suspend != nil && *oldJob.Spec.Suspend
		notStarted := oldJob.Status.StartTime == nil
		opts.AllowMutableSchedulingDirectives = suspended && notStarted
		if utilfeature.DefaultFeatureGate.Enabled(features.MutablePodResourcesForSuspendedJobs) {
			opts.AllowMutablePodResources = suspended && batchvalidation.IsConditionTrue(oldJob.Status.Conditions, batch.JobSuspended) && oldJob.Status.Active == 0
		}
		if utilfeature.DefaultFeatureGate.Enabled(features.MutableSchedulingDirectivesForSuspendedJobs) {
			opts.AllowMutableSchedulingDirectives = suspended && batchvalidation.IsConditionTrue(oldJob.Status.Conditions, batch.JobSuspended) && oldJob.Status.Active == 0
		}
		// Validation should not fail jobs if they don't have the new labels.
		// This can be removed once we have high confidence that both labels exist (1.30 at least)
		_, hadJobName := oldJob.Spec.Template.Labels[batch.JobNameLabel]
		_, hadControllerUid := oldJob.Spec.Template.Labels[batch.ControllerUidLabel]
		opts.RequirePrefixedLabels = hadJobName && hadControllerUid
	}
	return opts
}

// WarningsOnCreate returns warnings for the creation of the given object.
func (jobStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
	newJob := obj.(*batch.Job)
	var warnings []string
	if msgs := utilvalidation.IsDNS1123Label(newJob.Name); len(msgs) != 0 {
		warnings = append(warnings, fmt.Sprintf("metadata.name: this is used in Pod names and hostnames, which can result in surprising behavior; a DNS label is recommended: %v", msgs))
	}
	warnings = append(warnings, job.WarningsForJobSpec(ctx, field.NewPath("spec"), &newJob.Spec, nil)...)
	return warnings
}

// generateSelectorIfNeeded checks the job's manual selector flag and generates selector labels if the flag is true.