1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

fix(stack): EE-4213 Allow latest image to be pulled for stacks: backport backend logic (#7669)

This commit is contained in:
congs 2022-09-15 16:57:26 +12:00 committed by GitHub
parent fa162cafc1
commit 6078234d07
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 84 additions and 40 deletions

View file

@ -124,7 +124,7 @@ func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter,
doCleanUp := true
defer handler.cleanUp(stack, &doCleanUp)
config, configErr := handler.createComposeDeployConfig(r, stack, endpoint)
config, configErr := handler.createComposeDeployConfig(r, stack, endpoint, false)
if configErr != nil {
return configErr
}
@ -275,7 +275,7 @@ func (handler *Handler) createComposeStackFromGitRepository(w http.ResponseWrite
}
stack.GitConfig.ConfigHash = commitID
config, configErr := handler.createComposeDeployConfig(r, stack, endpoint)
config, configErr := handler.createComposeDeployConfig(r, stack, endpoint, false)
if configErr != nil {
return configErr
}
@ -386,7 +386,7 @@ func (handler *Handler) createComposeStackFromFileUpload(w http.ResponseWriter,
doCleanUp := true
defer handler.cleanUp(stack, &doCleanUp)
config, configErr := handler.createComposeDeployConfig(r, stack, endpoint)
config, configErr := handler.createComposeDeployConfig(r, stack, endpoint, false)
if configErr != nil {
return configErr
}
@ -408,14 +408,15 @@ func (handler *Handler) createComposeStackFromFileUpload(w http.ResponseWriter,
}
type composeStackDeploymentConfig struct {
stack *portainer.Stack
endpoint *portainer.Endpoint
registries []portainer.Registry
isAdmin bool
user *portainer.User
stack *portainer.Stack
endpoint *portainer.Endpoint
registries []portainer.Registry
isAdmin bool
user *portainer.User
forcePullImage bool
}
func (handler *Handler) createComposeDeployConfig(r *http.Request, stack *portainer.Stack, endpoint *portainer.Endpoint) (*composeStackDeploymentConfig, *httperror.HandlerError) {
func (handler *Handler) createComposeDeployConfig(r *http.Request, stack *portainer.Stack, endpoint *portainer.Endpoint, forcePullImage bool) (*composeStackDeploymentConfig, *httperror.HandlerError) {
securityContext, err := security.RetrieveRestrictedRequestContext(r)
if err != nil {
return nil, httperror.InternalServerError("Unable to retrieve info from request context", err)
@ -433,11 +434,12 @@ func (handler *Handler) createComposeDeployConfig(r *http.Request, stack *portai
filteredRegistries := security.FilterRegistries(registries, user, securityContext.UserMemberships, endpoint.ID)
config := &composeStackDeploymentConfig{
stack: stack,
endpoint: endpoint,
registries: filteredRegistries,
isAdmin: securityContext.IsAdmin,
user: user,
stack: stack,
endpoint: endpoint,
registries: filteredRegistries,
isAdmin: securityContext.IsAdmin,
user: user,
forcePullImage: forcePullImage,
}
return config, nil
@ -477,5 +479,5 @@ func (handler *Handler) deployComposeStack(config *composeStackDeploymentConfig,
}
}
return handler.StackDeployer.DeployComposeStack(config.stack, config.endpoint, config.registries, forceCreate)
return handler.StackDeployer.DeployComposeStack(config.stack, config.endpoint, config.registries, config.forcePullImage, forceCreate)
}

View file

@ -85,7 +85,7 @@ func (handler *Handler) createSwarmStackFromFileContent(w http.ResponseWriter, r
doCleanUp := true
defer handler.cleanUp(stack, &doCleanUp)
config, configErr := handler.createSwarmDeployConfig(r, stack, endpoint, false)
config, configErr := handler.createSwarmDeployConfig(r, stack, endpoint, false, true)
if configErr != nil {
return configErr
}
@ -226,7 +226,7 @@ func (handler *Handler) createSwarmStackFromGitRepository(w http.ResponseWriter,
}
stack.GitConfig.ConfigHash = commitID
config, configErr := handler.createSwarmDeployConfig(r, stack, endpoint, false)
config, configErr := handler.createSwarmDeployConfig(r, stack, endpoint, false, true)
if configErr != nil {
return configErr
}
@ -332,7 +332,7 @@ func (handler *Handler) createSwarmStackFromFileUpload(w http.ResponseWriter, r
doCleanUp := true
defer handler.cleanUp(stack, &doCleanUp)
config, configErr := handler.createSwarmDeployConfig(r, stack, endpoint, false)
config, configErr := handler.createSwarmDeployConfig(r, stack, endpoint, false, true)
if configErr != nil {
return configErr
}
@ -360,9 +360,10 @@ type swarmStackDeploymentConfig struct {
prune bool
isAdmin bool
user *portainer.User
pullImage bool
}
func (handler *Handler) createSwarmDeployConfig(r *http.Request, stack *portainer.Stack, endpoint *portainer.Endpoint, prune bool) (*swarmStackDeploymentConfig, *httperror.HandlerError) {
func (handler *Handler) createSwarmDeployConfig(r *http.Request, stack *portainer.Stack, endpoint *portainer.Endpoint, prune bool, pullImage bool) (*swarmStackDeploymentConfig, *httperror.HandlerError) {
securityContext, err := security.RetrieveRestrictedRequestContext(r)
if err != nil {
return nil, httperror.InternalServerError("Unable to retrieve info from request context", err)
@ -386,6 +387,7 @@ func (handler *Handler) createSwarmDeployConfig(r *http.Request, stack *portaine
prune: prune,
isAdmin: securityContext.IsAdmin,
user: user,
pullImage: pullImage,
}
return config, nil
@ -413,5 +415,5 @@ func (handler *Handler) deploySwarmStack(config *swarmStackDeploymentConfig) err
}
}
return handler.StackDeployer.DeploySwarmStack(config.stack, config.endpoint, config.registries, config.prune)
return handler.StackDeployer.DeploySwarmStack(config.stack, config.endpoint, config.registries, config.prune, config.pullImage)
}

View file

@ -189,7 +189,7 @@ func (handler *Handler) migrateStack(r *http.Request, stack *portainer.Stack, ne
}
func (handler *Handler) migrateComposeStack(r *http.Request, stack *portainer.Stack, next *portainer.Endpoint) *httperror.HandlerError {
config, configErr := handler.createComposeDeployConfig(r, stack, next)
config, configErr := handler.createComposeDeployConfig(r, stack, next, false)
if configErr != nil {
return configErr
}
@ -203,7 +203,7 @@ func (handler *Handler) migrateComposeStack(r *http.Request, stack *portainer.St
}
func (handler *Handler) migrateSwarmStack(r *http.Request, stack *portainer.Stack, next *portainer.Endpoint) *httperror.HandlerError {
config, configErr := handler.createSwarmDeployConfig(r, stack, next, true)
config, configErr := handler.createSwarmDeployConfig(r, stack, next, true, true)
if configErr != nil {
return configErr
}

View file

@ -134,7 +134,7 @@ func (handler *Handler) startStack(stack *portainer.Stack, endpoint *portainer.E
case portainer.DockerComposeStack:
return handler.ComposeStackManager.Up(context.TODO(), stack, endpoint, false)
case portainer.DockerSwarmStack:
return handler.SwarmStackManager.Deploy(stack, true, endpoint)
return handler.SwarmStackManager.Deploy(stack, true, true, endpoint)
}
return nil
}

View file

@ -23,6 +23,8 @@ type updateComposeStackPayload struct {
StackFileContent string `example:"version: 3\n services:\n web:\n image:nginx"`
// A list of environment(endpoint) variables used during stack deployment
Env []portainer.Pair
// Force a pulling to current image with the original tag though the image is already the latest
PullImage bool `example:"false"`
}
func (payload *updateComposeStackPayload) Validate(r *http.Request) error {
@ -39,6 +41,8 @@ type updateSwarmStackPayload struct {
Env []portainer.Pair
// Prune services that are no longer referenced (only available for Swarm stacks)
Prune bool `example:"true"`
// Force a pulling to current image with the original tag though the image is already the latest
PullImage bool `example:"false"`
}
func (payload *updateSwarmStackPayload) Validate(r *http.Request) error {
@ -199,7 +203,7 @@ func (handler *Handler) updateComposeStack(r *http.Request, stack *portainer.Sta
return httperror.InternalServerError("Unable to persist updated Compose file on disk", err)
}
config, configErr := handler.createComposeDeployConfig(r, stack, endpoint)
config, configErr := handler.createComposeDeployConfig(r, stack, endpoint, payload.PullImage)
if configErr != nil {
if rollbackErr := handler.FileService.RollbackStackFile(stackFolder, stack.EntryPoint); rollbackErr != nil {
log.Printf("[WARN] [stack,update] [message: rollback stack file error] [err: %s]", rollbackErr)
@ -250,7 +254,7 @@ func (handler *Handler) updateSwarmStack(r *http.Request, stack *portainer.Stack
return httperror.InternalServerError("Unable to persist updated Compose file on disk", err)
}
config, configErr := handler.createSwarmDeployConfig(r, stack, endpoint, payload.Prune)
config, configErr := handler.createSwarmDeployConfig(r, stack, endpoint, payload.Prune, payload.PullImage)
if configErr != nil {
if rollbackErr := handler.FileService.RollbackStackFile(stackFolder, stack.EntryPoint); rollbackErr != nil {
log.Printf("[WARN] [swarm,stack,update] [message: rollback stack file error] [err: %s]", rollbackErr)

View file

@ -25,6 +25,8 @@ type stackGitRedployPayload struct {
RepositoryPassword string
Env []portainer.Pair
Prune bool
// Force a pulling to current image with the original tag though the image is already the latest
PullImage bool `example:"false"`
}
func (payload *stackGitRedployPayload) Validate(r *http.Request) error {
@ -167,7 +169,7 @@ func (handler *Handler) stackGitRedeploy(w http.ResponseWriter, r *http.Request)
}
}()
httpErr := handler.deployStack(r, stack, endpoint)
httpErr := handler.deployStack(r, stack, payload.PullImage, endpoint)
if httpErr != nil {
return httpErr
}
@ -199,14 +201,14 @@ func (handler *Handler) stackGitRedeploy(w http.ResponseWriter, r *http.Request)
return response.JSON(w, stack)
}
func (handler *Handler) deployStack(r *http.Request, stack *portainer.Stack, endpoint *portainer.Endpoint) *httperror.HandlerError {
func (handler *Handler) deployStack(r *http.Request, stack *portainer.Stack, pullImage bool, endpoint *portainer.Endpoint) *httperror.HandlerError {
switch stack.Type {
case portainer.DockerSwarmStack:
prune := false
if stack.Option != nil {
prune = stack.Option.Prune
}
config, httpErr := handler.createSwarmDeployConfig(r, stack, endpoint, prune)
config, httpErr := handler.createSwarmDeployConfig(r, stack, endpoint, prune, pullImage)
if httpErr != nil {
return httpErr
}
@ -216,7 +218,7 @@ func (handler *Handler) deployStack(r *http.Request, stack *portainer.Stack, end
}
case portainer.DockerComposeStack:
config, httpErr := handler.createComposeDeployConfig(r, stack, endpoint)
config, httpErr := handler.createComposeDeployConfig(r, stack, endpoint, pullImage)
if httpErr != nil {
return httpErr
}