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:
parent
fa162cafc1
commit
6078234d07
13 changed files with 84 additions and 40 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue