From 5daef5445602c46f62915fd097a46da5eec703dd Mon Sep 17 00:00:00 2001 From: matias-portainer <104775949+matias-portainer@users.noreply.github.com> Date: Thu, 18 May 2023 17:58:42 -0300 Subject: [PATCH] fix(stacks): normalize stack name before performing actions EE-4839 (#8539) --- api/http/handler/stacks/handler.go | 2 +- api/http/handler/stacks/stack_delete.go | 14 +++++++++++++- api/http/handler/stacks/stack_start.go | 9 ++++++++- api/http/handler/stacks/stack_stop.go | 9 ++++++++- api/http/handler/stacks/stack_update.go | 4 ++++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/api/http/handler/stacks/handler.go b/api/http/handler/stacks/handler.go index caec10ab3..0f2c5cc50 100644 --- a/api/http/handler/stacks/handler.go +++ b/api/http/handler/stacks/handler.go @@ -136,7 +136,7 @@ func (handler *Handler) userCanManageStacks(securityContext *security.Restricted canCreate, err := handler.userCanCreateStack(securityContext, portainer.EndpointID(endpoint.ID)) if err != nil { - return false, fmt.Errorf("Failed to get user from the database: %w", err) + return false, fmt.Errorf("failed to get user from the database: %w", err) } return canCreate, nil diff --git a/api/http/handler/stacks/stack_delete.go b/api/http/handler/stacks/stack_delete.go index 3a5b68e0f..da2bd008f 100644 --- a/api/http/handler/stacks/stack_delete.go +++ b/api/http/handler/stacks/stack_delete.go @@ -109,7 +109,7 @@ func (handler *Handler) stackDelete(w http.ResponseWriter, r *http.Request) *htt return httperror.InternalServerError("Unable to verify user authorizations to validate stack deletion", err) } if !canManage { - errMsg := "Stack deletion is disabled for non-admin users" + errMsg := "stack deletion is disabled for non-admin users" return httperror.Forbidden(errMsg, fmt.Errorf(errMsg)) } @@ -188,17 +188,25 @@ func (handler *Handler) deleteExternalStack(r *http.Request, w http.ResponseWrit func (handler *Handler) deleteStack(userID portainer.UserID, stack *portainer.Stack, endpoint *portainer.Endpoint) error { if stack.Type == portainer.DockerSwarmStack { + stack.Name = handler.SwarmStackManager.NormalizeStackName(stack.Name) + if stackutils.IsGitStack(stack) { return handler.StackDeployer.UndeployRemoteSwarmStack(stack, endpoint) } + return handler.SwarmStackManager.Remove(stack, endpoint) } + if stack.Type == portainer.DockerComposeStack { + stack.Name = handler.ComposeStackManager.NormalizeStackName(stack.Name) + if stackutils.IsGitStack(stack) { return handler.StackDeployer.UndeployRemoteComposeStack(stack, endpoint) } + return handler.ComposeStackManager.Down(context.TODO(), stack, endpoint) } + if stack.Type == portainer.KubernetesStack { var manifestFiles []string @@ -210,6 +218,7 @@ func (handler *Handler) deleteStack(userID portainer.UserID, stack *portainer.St if err != nil { return errors.Wrap(err, "failed to create temp directory for deleting kub stack") } + defer os.RemoveAll(tmpDir) for _, fileName := range fileNames { @@ -233,8 +242,11 @@ func (handler *Handler) deleteStack(userID portainer.UserID, stack *portainer.St } else { manifestFiles = stackutils.GetStackFilePaths(stack, true) } + out, err := handler.KubernetesDeployer.Remove(userID, endpoint, manifestFiles, stack.Namespace) + return errors.WithMessagef(err, "failed to remove kubernetes resources: %q", out) } + return fmt.Errorf("unsupported stack type: %v", stack.Type) } diff --git a/api/http/handler/stacks/stack_start.go b/api/http/handler/stacks/stack_start.go index 38ac6c24b..f0bee2345 100644 --- a/api/http/handler/stacks/stack_start.go +++ b/api/http/handler/stacks/stack_start.go @@ -70,7 +70,7 @@ func (handler *Handler) stackStart(w http.ResponseWriter, r *http.Request) *http return httperror.InternalServerError("Unable to verify user authorizations to validate stack deletion", err) } if !canManage { - errMsg := "Stack management is disabled for non-admin users" + errMsg := "stack management is disabled for non-admin users" return httperror.Forbidden(errMsg, errors.New(errMsg)) } @@ -133,15 +133,22 @@ func (handler *Handler) stackStart(w http.ResponseWriter, r *http.Request) *http func (handler *Handler) startStack(stack *portainer.Stack, endpoint *portainer.Endpoint) error { switch stack.Type { case portainer.DockerComposeStack: + stack.Name = handler.ComposeStackManager.NormalizeStackName(stack.Name) + if stackutils.IsGitStack(stack) { return handler.StackDeployer.StartRemoteComposeStack(stack, endpoint) } + return handler.ComposeStackManager.Up(context.TODO(), stack, endpoint, false) case portainer.DockerSwarmStack: + stack.Name = handler.SwarmStackManager.NormalizeStackName(stack.Name) + if stackutils.IsGitStack(stack) { return handler.StackDeployer.StartRemoteSwarmStack(stack, endpoint) } + return handler.SwarmStackManager.Deploy(stack, true, true, endpoint) } + return nil } diff --git a/api/http/handler/stacks/stack_stop.go b/api/http/handler/stacks/stack_stop.go index 0063f8bf8..24a7dec0d 100644 --- a/api/http/handler/stacks/stack_stop.go +++ b/api/http/handler/stacks/stack_stop.go @@ -81,7 +81,7 @@ func (handler *Handler) stackStop(w http.ResponseWriter, r *http.Request) *httpe return httperror.InternalServerError("Unable to verify user authorizations to validate stack deletion", err) } if !canManage { - errMsg := "Stack management is disabled for non-admin users" + errMsg := "stack management is disabled for non-admin users" return httperror.Forbidden(errMsg, errors.New(errMsg)) } @@ -117,15 +117,22 @@ func (handler *Handler) stackStop(w http.ResponseWriter, r *http.Request) *httpe func (handler *Handler) stopStack(stack *portainer.Stack, endpoint *portainer.Endpoint) error { switch stack.Type { case portainer.DockerComposeStack: + stack.Name = handler.ComposeStackManager.NormalizeStackName(stack.Name) + if stackutils.IsGitStack(stack) { return handler.StackDeployer.StopRemoteComposeStack(stack, endpoint) } + return handler.ComposeStackManager.Down(context.TODO(), stack, endpoint) case portainer.DockerSwarmStack: + stack.Name = handler.SwarmStackManager.NormalizeStackName(stack.Name) + if stackutils.IsGitStack(stack) { return handler.StackDeployer.StopRemoteSwarmStack(stack, endpoint) } + return handler.SwarmStackManager.Remove(stack, endpoint) } + return nil } diff --git a/api/http/handler/stacks/stack_update.go b/api/http/handler/stacks/stack_update.go index 85a8faa10..3431f65a1 100644 --- a/api/http/handler/stacks/stack_update.go +++ b/api/http/handler/stacks/stack_update.go @@ -166,8 +166,12 @@ func (handler *Handler) stackUpdate(w http.ResponseWriter, r *http.Request) *htt func (handler *Handler) updateAndDeployStack(r *http.Request, stack *portainer.Stack, endpoint *portainer.Endpoint) *httperror.HandlerError { if stack.Type == portainer.DockerSwarmStack { + stack.Name = handler.SwarmStackManager.NormalizeStackName(stack.Name) + return handler.updateSwarmStack(r, stack, endpoint) } else if stack.Type == portainer.DockerComposeStack { + stack.Name = handler.ComposeStackManager.NormalizeStackName(stack.Name) + return handler.updateComposeStack(r, stack, endpoint) } else if stack.Type == portainer.KubernetesStack { return handler.updateKubernetesStack(r, stack, endpoint)