controllers/webhooks/validation/duplicate_validator.go
package validation import ( "context" "code.cloudfoundry.org/korifi/controllers/webhooks" "github.com/go-logr/logr" k8serrors "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/controller-runtime/pkg/client") const DuplicateNameErrorType = "DuplicateNameError" type DuplicateValidator struct { nameRegistry webhooks.NameRegistry} func NewDuplicateValidator(nameRegistry webhooks.NameRegistry) *DuplicateValidator { return &DuplicateValidator{ nameRegistry: nameRegistry, }} func (v DuplicateValidator) ValidateCreate(ctx context.Context, logger logr.Logger, namespace string, obj webhooks.UniqueClientObject) error { logger = logger.WithName("duplicateValidator.ValidateCreate") err := v.nameRegistry.RegisterName(ctx, namespace, obj.UniqueName(), obj.GetNamespace(), obj.GetName()) if err != nil { logger.Info("failed to register name during create", "name", obj.UniqueName(), "namespace", namespace, "reason", err, ) if k8serrors.IsAlreadyExists(err) { return duplicateError(obj) } return unknownError() } return nil} Method `DuplicateValidator.ValidateUpdate` has 52 lines of code (exceeds 50 allowed). Consider refactoring.func (v DuplicateValidator) ValidateUpdate(ctx context.Context, logger logr.Logger, namespace string, oldObj, obj webhooks.UniqueClientObject) error { if oldObj.UniqueName() == obj.UniqueName() { return nil } logger = logger. WithName("duplicateValidator.ValidateUpdate"). WithValues("namespace", namespace, "oldName", oldObj.UniqueName(), "newName", obj.UniqueName()) err := v.nameRegistry.TryLockName(ctx, namespace, oldObj.UniqueName()) if err != nil { logger.Info("failed to acquire lock on old name", "reason", err) if k8serrors.IsNotFound(err) { isOwned, ownershipErr := v.nameRegistry.CheckNameOwnership(ctx, namespace, obj.UniqueName(), obj.GetNamespace(), obj.GetName()) if ownershipErr != nil { logger.Error(ownershipErr, "failed to check ownership on new name") return unknownError() } if isOwned { logger.Info("unique name is already owned by updated object", "name", obj.UniqueName(), "updatedObjectKind", obj.GetObjectKind(), "object", client.ObjectKeyFromObject(obj), ) return nil } } return unknownError() } logger.V(1).Info("locked-old-name") err = v.nameRegistry.RegisterName(ctx, namespace, obj.UniqueName(), obj.GetNamespace(), obj.GetName()) if err != nil { // cannot register new name, so unlock old registry entry allowing future renames unlockErr := v.nameRegistry.UnlockName(ctx, namespace, oldObj.UniqueName()) if unlockErr != nil { // A locked registry entry will remain, so future name updates will fail until operator intervenes logger.Info("failed to release lock on old name", "reason", unlockErr, ) } logger.Info("failed to register new name during update", "reason", err, ) if k8serrors.IsAlreadyExists(err) { return duplicateError(obj) } return unknownError() } logger.V(1).Info("registered-new-name") err = v.nameRegistry.DeregisterName(ctx, namespace, oldObj.UniqueName()) if err != nil { // We cannot unclaim the old name. It will remain claimed until an operator intervenes. logger.Info("failed to deregister old name during update", "reason", err, ) } logger.V(1).Info("deregistered-old-name") return nil} func (v DuplicateValidator) ValidateDelete(ctx context.Context, logger logr.Logger, namespace string, obj webhooks.UniqueClientObject) error { logger = logger.WithName("duplicateValidator.ValidateDelete") err := v.nameRegistry.DeregisterName(ctx, namespace, obj.UniqueName()) if err != nil { logger.Info("failed to deregister name during delete", "namespace", namespace, "name", obj.UniqueName(), "reason", err, ) if k8serrors.IsNotFound(err) { return nil } return unknownError() } return nil} func duplicateError(obj webhooks.UniqueClientObject) error { return ValidationError{ Type: DuplicateNameErrorType, Message: obj.UniqueValidationErrorMessage(), }.ExportJSONError()} func unknownError() error { return ValidationError{ Type: UnknownErrorType, Message: UnknownErrorMessage, }.ExportJSONError()} // check interface is implemented correctlyvar _ webhooks.NameValidator = DuplicateValidator{}