diff --git a/api/http/handler/registries/registry_create.go b/api/http/handler/registries/registry_create.go index 724b33aff..bb736fb50 100644 --- a/api/http/handler/registries/registry_create.go +++ b/api/http/handler/registries/registry_create.go @@ -126,6 +126,9 @@ func (handler *Handler) registryCreate(w http.ResponseWriter, r *http.Request) * return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve registries from the database", err} } for _, r := range registries { + if r.Name == registry.Name { + return &httperror.HandlerError{http.StatusConflict, "Another registry with the same name already exists", errors.New("A registry is already defined with this name")} + } if handler.registriesHaveSameURLAndCredentials(&r, registry) { return &httperror.HandlerError{http.StatusConflict, "Another registry with the same URL and credentials already exists", errors.New("A registry is already defined for this URL and credentials")} } diff --git a/api/http/handler/registries/registry_update.go b/api/http/handler/registries/registry_update.go index cf0a6a51a..3daa84afe 100644 --- a/api/http/handler/registries/registry_update.go +++ b/api/http/handler/registries/registry_update.go @@ -77,6 +77,11 @@ func (handler *Handler) registryUpdate(w http.ResponseWriter, r *http.Request) * return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a registry with the specified identifier inside the database", err} } + registries, err := handler.DataStore.Registry().Registries() + if err != nil { + return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve registries from the database", err} + } + var payload registryUpdatePayload err = request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { @@ -86,6 +91,15 @@ func (handler *Handler) registryUpdate(w http.ResponseWriter, r *http.Request) * if payload.Name != nil { registry.Name = *payload.Name } + // enforce name uniqueness across registries + // check is performed even if Name didn't change (Name not in payload) as we need + // to enforce this rule on updates not performed with frontend (e.g. on direct API requests) + // see https://portainer.atlassian.net/browse/EE-2706 for more details + for _, r := range registries { + if r.ID != registry.ID && r.Name == registry.Name { + return &httperror.HandlerError{http.StatusConflict, "Another registry with the same name already exists", errors.New("A registry is already defined with this name")} + } + } if registry.Type == portainer.ProGetRegistry && payload.BaseURL != nil { registry.BaseURL = *payload.BaseURL @@ -129,10 +143,6 @@ func (handler *Handler) registryUpdate(w http.ResponseWriter, r *http.Request) * shouldUpdateSecrets = shouldUpdateSecrets || (*payload.URL != registry.URL) registry.URL = *payload.URL - registries, err := handler.DataStore.Registry().Registries() - if err != nil { - return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve registries from the database", err} - } for _, r := range registries { if r.ID != registry.ID && handler.registriesHaveSameURLAndCredentials(&r, registry) { diff --git a/app/portainer/__module.js b/app/portainer/__module.js index 028137979..b2f861728 100644 --- a/app/portainer/__module.js +++ b/app/portainer/__module.js @@ -401,8 +401,7 @@ angular url: '/:id', views: { 'content@': { - templateUrl: './views/registries/edit/registry.html', - controller: 'RegistryController', + component: 'editRegistry', }, }, }; diff --git a/app/portainer/components/forms/registry-form-aws-ecr/registry-form-ecr.html b/app/portainer/components/forms/registry-form-aws-ecr/registry-form-ecr.html index 93b11c9c0..529ecfe0e 100644 --- a/app/portainer/components/forms/registry-form-aws-ecr/registry-form-ecr.html +++ b/app/portainer/components/forms/registry-form-aws-ecr/registry-form-ecr.html @@ -1,4 +1,4 @@ -