From 59ec22f70634cabdaad4cb8b08ed8c7dde99f335 Mon Sep 17 00:00:00 2001 From: Hui Date: Mon, 17 Jan 2022 10:20:45 +1300 Subject: [PATCH] fix(docker-compose): add logic control for docker compose force recreate EE-2356 --- api/exec/compose_stack.go | 4 ++-- api/exec/compose_stack_integration_test.go | 2 +- api/go.mod | 2 +- api/go.sum | 4 ++-- api/http/handler/stacks/create_compose_stack.go | 10 +++++----- api/http/handler/stacks/stack_migrate.go | 2 +- api/http/handler/stacks/stack_start.go | 2 +- api/http/handler/stacks/stack_update.go | 2 +- api/http/handler/stacks/stack_update_git_redeploy.go | 2 +- api/portainer.go | 2 +- api/stacks/deploy.go | 4 +++- api/stacks/deploy_test.go | 2 +- api/stacks/deployer.go | 6 +++--- 13 files changed, 23 insertions(+), 21 deletions(-) diff --git a/api/exec/compose_stack.go b/api/exec/compose_stack.go index 76fd39585..f80af924d 100644 --- a/api/exec/compose_stack.go +++ b/api/exec/compose_stack.go @@ -46,7 +46,7 @@ func (manager *ComposeStackManager) ComposeSyntaxMaxVersion() string { } // Up builds, (re)creates and starts containers in the background. Wraps `docker-compose up -d` command -func (manager *ComposeStackManager) Up(ctx context.Context, stack *portainer.Stack, endpoint *portainer.Endpoint) error { +func (manager *ComposeStackManager) Up(ctx context.Context, stack *portainer.Stack, endpoint *portainer.Endpoint, forceRereate bool) error { url, proxy, err := manager.fetchEndpointProxy(endpoint) if err != nil { return errors.Wrap(err, "failed to fetch environment proxy") @@ -62,7 +62,7 @@ func (manager *ComposeStackManager) Up(ctx context.Context, stack *portainer.Sta } filePaths := stackutils.GetStackFilePaths(stack) - err = manager.deployer.Deploy(ctx, stack.ProjectPath, url, stack.Name, filePaths, envFilePath) + err = manager.deployer.Deploy(ctx, stack.ProjectPath, url, stack.Name, filePaths, envFilePath, forceRereate) return errors.Wrap(err, "failed to deploy a stack") } diff --git a/api/exec/compose_stack_integration_test.go b/api/exec/compose_stack_integration_test.go index 27209d57d..5557b5173 100644 --- a/api/exec/compose_stack_integration_test.go +++ b/api/exec/compose_stack_integration_test.go @@ -50,7 +50,7 @@ func Test_UpAndDown(t *testing.T) { ctx := context.TODO() - err = w.Up(ctx, stack, endpoint) + err = w.Up(ctx, stack, endpoint, false) if err != nil { t.Fatalf("Error calling docker-compose up: %s", err) } diff --git a/api/go.mod b/api/go.mod index e28d8f854..0ee7f6e4d 100644 --- a/api/go.mod +++ b/api/go.mod @@ -29,7 +29,7 @@ require ( github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6 github.com/pkg/errors v0.9.1 - github.com/portainer/docker-compose-wrapper v0.0.0-20211018221743-10a04c9d4f19 + github.com/portainer/docker-compose-wrapper v0.0.0-20220113045708-6569596db840 github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108 github.com/portainer/libhttp v0.0.0-20211021135806-13e6c55c5fbc diff --git a/api/go.sum b/api/go.sum index 768f10a19..4a476664f 100644 --- a/api/go.sum +++ b/api/go.sum @@ -611,8 +611,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/portainer/docker-compose-wrapper v0.0.0-20211018221743-10a04c9d4f19 h1:tG2gU4mkm5yElj35XpU3lgllOYQxN3kaM1Jab7AqTDs= -github.com/portainer/docker-compose-wrapper v0.0.0-20211018221743-10a04c9d4f19/go.mod h1:WxDlJWZxCnicdLCPnLNEv7/gRhjeIVuCGmsv+iOPH3c= +github.com/portainer/docker-compose-wrapper v0.0.0-20220113045708-6569596db840 h1:Nciddt8Y8G8nTMmyDfWxeN23PZUcsqbZE2zOFB/F1xg= +github.com/portainer/docker-compose-wrapper v0.0.0-20220113045708-6569596db840/go.mod h1:WxDlJWZxCnicdLCPnLNEv7/gRhjeIVuCGmsv+iOPH3c= github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a h1:qY8TbocN75n5PDl16o0uVr5MevtM5IhdwSelXEd4nFM= github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a/go.mod h1:n54EEIq+MM0NNtqLeCby8ljL+l275VpolXO0ibHegLE= github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108 h1:5e8KAnDa2G3cEHK7aV/ue8lOaoQwBZUzoALslwWkR04= diff --git a/api/http/handler/stacks/create_compose_stack.go b/api/http/handler/stacks/create_compose_stack.go index d38de668b..a90486fa6 100644 --- a/api/http/handler/stacks/create_compose_stack.go +++ b/api/http/handler/stacks/create_compose_stack.go @@ -129,7 +129,7 @@ func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter, return configErr } - err = handler.deployComposeStack(config) + err = handler.deployComposeStack(config, false) if err != nil { return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} } @@ -283,7 +283,7 @@ func (handler *Handler) createComposeStackFromGitRepository(w http.ResponseWrite return configErr } - err = handler.deployComposeStack(config) + err = handler.deployComposeStack(config, false) if err != nil { return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} } @@ -394,7 +394,7 @@ func (handler *Handler) createComposeStackFromFileUpload(w http.ResponseWriter, return configErr } - err = handler.deployComposeStack(config) + err = handler.deployComposeStack(config, false) if err != nil { return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} } @@ -451,7 +451,7 @@ func (handler *Handler) createComposeDeployConfig(r *http.Request, stack *portai // to login/logout, which will generate the required data in the config.json file and then // clean it. Hence the use of the mutex. // We should contribute to libcompose to support authentication without using the config.json file. -func (handler *Handler) deployComposeStack(config *composeStackDeploymentConfig) error { +func (handler *Handler) deployComposeStack(config *composeStackDeploymentConfig, forceCreate bool) error { isAdminOrEndpointAdmin, err := handler.userIsAdminOrEndpointAdmin(config.user, config.endpoint.ID) if err != nil { return errors.Wrap(err, "failed to check user priviliges deploying a stack") @@ -480,5 +480,5 @@ func (handler *Handler) deployComposeStack(config *composeStackDeploymentConfig) } } - return handler.StackDeployer.DeployComposeStack(config.stack, config.endpoint, config.registries) + return handler.StackDeployer.DeployComposeStack(config.stack, config.endpoint, config.registries, forceCreate) } diff --git a/api/http/handler/stacks/stack_migrate.go b/api/http/handler/stacks/stack_migrate.go index 44c6b5d17..fbbdbd704 100644 --- a/api/http/handler/stacks/stack_migrate.go +++ b/api/http/handler/stacks/stack_migrate.go @@ -177,7 +177,7 @@ func (handler *Handler) migrateComposeStack(r *http.Request, stack *portainer.St return configErr } - err := handler.deployComposeStack(config) + err := handler.deployComposeStack(config, false) if err != nil { return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} } diff --git a/api/http/handler/stacks/stack_start.go b/api/http/handler/stacks/stack_start.go index 28c5c50e9..9cae241de 100644 --- a/api/http/handler/stacks/stack_start.go +++ b/api/http/handler/stacks/stack_start.go @@ -123,7 +123,7 @@ 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: - return handler.ComposeStackManager.Up(context.TODO(), stack, endpoint) + return handler.ComposeStackManager.Up(context.TODO(), stack, endpoint, false) case portainer.DockerSwarmStack: return handler.SwarmStackManager.Deploy(stack, true, endpoint) } diff --git a/api/http/handler/stacks/stack_update.go b/api/http/handler/stacks/stack_update.go index 2a757dc53..ac60dbf57 100644 --- a/api/http/handler/stacks/stack_update.go +++ b/api/http/handler/stacks/stack_update.go @@ -190,7 +190,7 @@ func (handler *Handler) updateComposeStack(r *http.Request, stack *portainer.Sta return configErr } - err = handler.deployComposeStack(config) + err = handler.deployComposeStack(config, false) if err != nil { return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} } diff --git a/api/http/handler/stacks/stack_update_git_redeploy.go b/api/http/handler/stacks/stack_update_git_redeploy.go index 834173f28..d18551a9c 100644 --- a/api/http/handler/stacks/stack_update_git_redeploy.go +++ b/api/http/handler/stacks/stack_update_git_redeploy.go @@ -206,7 +206,7 @@ func (handler *Handler) deployStack(r *http.Request, stack *portainer.Stack, end return httpErr } - if err := handler.deployComposeStack(config); err != nil { + if err := handler.deployComposeStack(config, true); err != nil { return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} } diff --git a/api/portainer.go b/api/portainer.go index 2a990da87..93e7a45f3 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -1150,7 +1150,7 @@ type ( ComposeStackManager interface { ComposeSyntaxMaxVersion() string NormalizeStackName(name string) string - Up(ctx context.Context, stack *Stack, endpoint *Endpoint) error + Up(ctx context.Context, stack *Stack, endpoint *Endpoint, forceRereate bool) error Down(ctx context.Context, stack *Stack, endpoint *Endpoint) error } diff --git a/api/stacks/deploy.go b/api/stacks/deploy.go index e1020a63f..3e7180687 100644 --- a/api/stacks/deploy.go +++ b/api/stacks/deploy.go @@ -21,6 +21,8 @@ func (e *StackAuthorMissingErr) Error() string { return fmt.Sprintf("stack's %v author %s is missing", e.stackID, e.authorName) } +// RedeployWhenChanged pull and redeploy the stack when git repo changed +// Stack will always be redeployed if force deployment is set to true func RedeployWhenChanged(stackID portainer.StackID, deployer StackDeployer, datastore dataservices.DataStore, gitService portainer.GitService) error { logger := log.WithFields(log.Fields{"stackID": stackID}) logger.Debug("redeploying stack") @@ -87,7 +89,7 @@ func RedeployWhenChanged(stackID portainer.StackID, deployer StackDeployer, data switch stack.Type { case portainer.DockerComposeStack: - err := deployer.DeployComposeStack(stack, endpoint, registries) + err := deployer.DeployComposeStack(stack, endpoint, registries, false) if err != nil { return errors.WithMessagef(err, "failed to deploy a docker compose stack %v", stackID) } diff --git a/api/stacks/deploy_test.go b/api/stacks/deploy_test.go index c617a1496..3620e53c4 100644 --- a/api/stacks/deploy_test.go +++ b/api/stacks/deploy_test.go @@ -32,7 +32,7 @@ func (s *noopDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *portai return nil } -func (s *noopDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry) error { +func (s *noopDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forceRereate bool) error { return nil } diff --git a/api/stacks/deployer.go b/api/stacks/deployer.go index 714bae066..80bd86384 100644 --- a/api/stacks/deployer.go +++ b/api/stacks/deployer.go @@ -14,7 +14,7 @@ import ( type StackDeployer interface { DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune bool) error - DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry) error + DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forceRereate bool) error DeployKubernetesStack(stack *portainer.Stack, endpoint *portainer.Endpoint, user *portainer.User) error } @@ -45,14 +45,14 @@ func (d *stackDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *porta return d.swarmStackManager.Deploy(stack, prune, endpoint) } -func (d *stackDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry) error { +func (d *stackDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forceRereate bool) error { d.lock.Lock() defer d.lock.Unlock() d.swarmStackManager.Login(registries, endpoint) defer d.swarmStackManager.Logout(endpoint) - return d.composeStackManager.Up(context.TODO(), stack, endpoint) + return d.composeStackManager.Up(context.TODO(), stack, endpoint, forceRereate) } func (d *stackDeployer) DeployKubernetesStack(stack *portainer.Stack, endpoint *portainer.Endpoint, user *portainer.User) error {