Repository: kubernetes/kubernetes
File: pkg/registry/core/replicationcontroller/strategy.go (Go)

Code before:
	// the burden of managing the status onto the clients because we can't (in general)
	// know here what version of spec the writer of the status has seen. It may seem like
	// we can at first -- since obj contains spec -- but in the future we will probably make
	// status its own object, and even if we don't, writes may be the result of a
	// read-update-write loop, so the contents of spec may not actually be the spec that
	// the controller has *seen*.
	if !apiequality.Semantic.DeepEqual(oldController.Spec, newController.Spec) {
		newController.Generation = oldController.Generation + 1
	}
}

// Validate validates a new replication controller.
func (rcStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
	controller := obj.(*api.ReplicationController)
	opts := pod.GetValidationOptionsFromPodTemplate(controller.Spec.Template, nil)

	// Run imperative validation
	allErrs := corevalidation.ValidateReplicationController(controller, opts)

	// If DeclarativeValidation feature gate is enabled, run both validations
	if utilfeature.DefaultFeatureGate.Enabled(features.DeclarativeValidation) {
		// Determine if takeover is enabled
		takeover := utilfeature.DefaultFeatureGate.Enabled(features.DeclarativeValidationTakeover)

		// Run declarative validation with panic recovery
		declarativeErrs := rest.ValidateDeclarativelyWithRecovery(ctx, nil, legacyscheme.Scheme, obj, takeover)

		// Compare imperative and declarative errors and log + emit metric if there's a mismatch
		rest.CompareDeclarativeErrorsAndEmitMismatches(allErrs, declarativeErrs, takeover)

		// Only apply declarative errors if takeover is enabled
		if takeover {
			allErrs = append(allErrs.RemoveCoveredByDeclarative(), declarativeErrs...)
		}
	}
	return allErrs
}

// WarningsOnCreate returns warnings for the creation of the given object.
func (rcStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
	newRC := obj.(*api.ReplicationController)
	var warnings []string
	if msgs := utilvalidation.IsDNS1123Label(newRC.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, pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), newRC.Spec.Template, nil)...)
	return warnings
}

// Canonicalize normalizes the object after validation.
func (rcStrategy) Canonicalize(obj runtime.Object) {

Review comment (bug):
```suggestion
		declarativeErrs := rest.ValidateDeclarativelyWithRecovery(ctx, nil, legacyscheme.Scheme, controller, takeover)
```

If we do this, our "standard" pattern that people will copy/paste will ensure that we don't validate the wrong runtime.Object type for a given request.

Code after:
	// the burden of managing the status onto the clients because we can't (in general)
	// know here what version of spec the writer of the status has seen. It may seem like
	// we can at first -- since obj contains spec -- but in the future we will probably make
	// status its own object, and even if we don't, writes may be the result of a
	// read-update-write loop, so the contents of spec may not actually be the spec that
	// the controller has *seen*.
	if !apiequality.Semantic.DeepEqual(oldController.Spec, newController.Spec) {
		newController.Generation = oldController.Generation + 1
	}
}

// Validate validates a new replication controller.
func (rcStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
	controller := obj.(*api.ReplicationController)
	opts := pod.GetValidationOptionsFromPodTemplate(controller.Spec.Template, nil)

	// Run imperative validation
	allErrs := corevalidation.ValidateReplicationController(controller, opts)

	// If DeclarativeValidation feature gate is enabled, also run declarative validation
	if utilfeature.DefaultFeatureGate.Enabled(features.DeclarativeValidation) {
		// Determine if takeover is enabled
		takeover := utilfeature.DefaultFeatureGate.Enabled(features.DeclarativeValidationTakeover)

		// Run declarative validation with panic recovery
		declarativeErrs := rest.ValidateDeclarativelyWithRecovery(ctx, nil, legacyscheme.Scheme, controller, takeover)

		// Compare imperative and declarative errors and log + emit metric if there's a mismatch
		rest.CompareDeclarativeErrorsAndEmitMismatches(ctx, allErrs, declarativeErrs, takeover)

		// Only apply declarative errors if takeover is enabled
		if takeover {
			allErrs = append(allErrs.RemoveCoveredByDeclarative(), declarativeErrs...)
		}
	}
	return allErrs
}

// WarningsOnCreate returns warnings for the creation of the given object.
func (rcStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
	newRC := obj.(*api.ReplicationController)
	var warnings []string
	if msgs := utilvalidation.IsDNS1123Label(newRC.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, pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), newRC.Spec.Template, nil)...)
	return warnings
}

// Canonicalize normalizes the object after validation.
func (rcStrategy) Canonicalize(obj runtime.Object) {