fix(docker-compose): add logic control for docker compose force recreate EE-2356

pull/4499/merge
Hui 2022-01-17 10:20:45 +13:00 committed by GitHub
parent c47e840b37
commit 59ec22f706
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 23 additions and 21 deletions

View File

@ -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 // 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) url, proxy, err := manager.fetchEndpointProxy(endpoint)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to fetch environment proxy") 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) 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") return errors.Wrap(err, "failed to deploy a stack")
} }

View File

@ -50,7 +50,7 @@ func Test_UpAndDown(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
err = w.Up(ctx, stack, endpoint) err = w.Up(ctx, stack, endpoint, false)
if err != nil { if err != nil {
t.Fatalf("Error calling docker-compose up: %s", err) t.Fatalf("Error calling docker-compose up: %s", err)
} }

View File

@ -29,7 +29,7 @@ require (
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c
github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6 github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6
github.com/pkg/errors v0.9.1 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/libcrypto v0.0.0-20210422035235-c652195c5c3a
github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108 github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108
github.com/portainer/libhttp v0.0.0-20211021135806-13e6c55c5fbc github.com/portainer/libhttp v0.0.0-20211021135806-13e6c55c5fbc

View File

@ -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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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-20220113045708-6569596db840 h1:Nciddt8Y8G8nTMmyDfWxeN23PZUcsqbZE2zOFB/F1xg=
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/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 h1:qY8TbocN75n5PDl16o0uVr5MevtM5IhdwSelXEd4nFM=
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a/go.mod h1:n54EEIq+MM0NNtqLeCby8ljL+l275VpolXO0ibHegLE= 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= github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108 h1:5e8KAnDa2G3cEHK7aV/ue8lOaoQwBZUzoALslwWkR04=

View File

@ -129,7 +129,7 @@ func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter,
return configErr return configErr
} }
err = handler.deployComposeStack(config) err = handler.deployComposeStack(config, false)
if err != nil { if err != nil {
return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err}
} }
@ -283,7 +283,7 @@ func (handler *Handler) createComposeStackFromGitRepository(w http.ResponseWrite
return configErr return configErr
} }
err = handler.deployComposeStack(config) err = handler.deployComposeStack(config, false)
if err != nil { if err != nil {
return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err}
} }
@ -394,7 +394,7 @@ func (handler *Handler) createComposeStackFromFileUpload(w http.ResponseWriter,
return configErr return configErr
} }
err = handler.deployComposeStack(config) err = handler.deployComposeStack(config, false)
if err != nil { if err != nil {
return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} 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 // to login/logout, which will generate the required data in the config.json file and then
// clean it. Hence the use of the mutex. // clean it. Hence the use of the mutex.
// We should contribute to libcompose to support authentication without using the config.json file. // 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) isAdminOrEndpointAdmin, err := handler.userIsAdminOrEndpointAdmin(config.user, config.endpoint.ID)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to check user priviliges deploying a stack") 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)
} }

View File

@ -177,7 +177,7 @@ func (handler *Handler) migrateComposeStack(r *http.Request, stack *portainer.St
return configErr return configErr
} }
err := handler.deployComposeStack(config) err := handler.deployComposeStack(config, false)
if err != nil { if err != nil {
return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err}
} }

View File

@ -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 { func (handler *Handler) startStack(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
switch stack.Type { switch stack.Type {
case portainer.DockerComposeStack: case portainer.DockerComposeStack:
return handler.ComposeStackManager.Up(context.TODO(), stack, endpoint) return handler.ComposeStackManager.Up(context.TODO(), stack, endpoint, false)
case portainer.DockerSwarmStack: case portainer.DockerSwarmStack:
return handler.SwarmStackManager.Deploy(stack, true, endpoint) return handler.SwarmStackManager.Deploy(stack, true, endpoint)
} }

View File

@ -190,7 +190,7 @@ func (handler *Handler) updateComposeStack(r *http.Request, stack *portainer.Sta
return configErr return configErr
} }
err = handler.deployComposeStack(config) err = handler.deployComposeStack(config, false)
if err != nil { if err != nil {
return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err} return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err}
} }

View File

@ -206,7 +206,7 @@ func (handler *Handler) deployStack(r *http.Request, stack *portainer.Stack, end
return httpErr 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} return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: err.Error(), Err: err}
} }

View File

@ -1150,7 +1150,7 @@ type (
ComposeStackManager interface { ComposeStackManager interface {
ComposeSyntaxMaxVersion() string ComposeSyntaxMaxVersion() string
NormalizeStackName(name string) 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 Down(ctx context.Context, stack *Stack, endpoint *Endpoint) error
} }

View File

@ -21,6 +21,8 @@ func (e *StackAuthorMissingErr) Error() string {
return fmt.Sprintf("stack's %v author %s is missing", e.stackID, e.authorName) 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 { func RedeployWhenChanged(stackID portainer.StackID, deployer StackDeployer, datastore dataservices.DataStore, gitService portainer.GitService) error {
logger := log.WithFields(log.Fields{"stackID": stackID}) logger := log.WithFields(log.Fields{"stackID": stackID})
logger.Debug("redeploying stack") logger.Debug("redeploying stack")
@ -87,7 +89,7 @@ func RedeployWhenChanged(stackID portainer.StackID, deployer StackDeployer, data
switch stack.Type { switch stack.Type {
case portainer.DockerComposeStack: case portainer.DockerComposeStack:
err := deployer.DeployComposeStack(stack, endpoint, registries) err := deployer.DeployComposeStack(stack, endpoint, registries, false)
if err != nil { if err != nil {
return errors.WithMessagef(err, "failed to deploy a docker compose stack %v", stackID) return errors.WithMessagef(err, "failed to deploy a docker compose stack %v", stackID)
} }

View File

@ -32,7 +32,7 @@ func (s *noopDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *portai
return nil 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 return nil
} }

View File

@ -14,7 +14,7 @@ import (
type StackDeployer interface { type StackDeployer interface {
DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune bool) error 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 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) 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() d.lock.Lock()
defer d.lock.Unlock() defer d.lock.Unlock()
d.swarmStackManager.Login(registries, endpoint) d.swarmStackManager.Login(registries, endpoint)
defer d.swarmStackManager.Logout(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 { func (d *stackDeployer) DeployKubernetesStack(stack *portainer.Stack, endpoint *portainer.Endpoint, user *portainer.User) error {