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

feat(system): upgrade on swarm [EE-5848] (#11728)

Co-authored-by: Chaim Lev-Ari <chaim.levi-ari@portainer.io>
Co-authored-by: LP B <xAt0mZ@users.noreply.github.com>
This commit is contained in:
Chaim Lev-Ari 2024-09-20 19:00:38 +03:00 committed by GitHub
parent 3cb484f06a
commit 6f84317e7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 362 additions and 158 deletions

View file

@ -1,26 +1,25 @@
package upgrade
import (
"bytes"
"context"
"fmt"
"os"
"strings"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/docker/docker/api/types/image"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/filesystem"
"github.com/portainer/portainer/pkg/libstack"
"github.com/cbroglie/mustache"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)
func (service *service) upgradeDocker(licenseKey, version, envType string) error {
func (service *service) upgradeDocker(environment *portainer.Endpoint, licenseKey, version string, envType string) error {
ctx := context.TODO()
templateName := filesystem.JoinPaths(service.assetsPath, "mustache-templates", mustacheUpgradeDockerTemplateFile)
portainerImagePrefix := os.Getenv(portainerImagePrefixEnvVar)
@ -30,15 +29,16 @@ func (service *service) upgradeDocker(licenseKey, version, envType string) error
image := fmt.Sprintf("%s:%s", portainerImagePrefix, version)
skipPullImage := os.Getenv(skipPullImageEnvVar)
skipPullImageEnv := os.Getenv(skipPullImageEnvVar)
skipPullImage := skipPullImageEnv != ""
if err := service.checkImageForDocker(ctx, image, skipPullImage != ""); err != nil {
if err := service.checkImageForDocker(ctx, environment, image, skipPullImage); err != nil {
return err
}
composeFile, err := mustache.RenderFile(templateName, map[string]string{
"image": image,
"skip_pull_image": skipPullImage,
"skip_pull_image": skipPullImageEnv,
"updater_image": os.Getenv(updaterImageEnvVar),
"license": licenseKey,
"envType": envType,
@ -52,13 +52,10 @@ func (service *service) upgradeDocker(licenseKey, version, envType string) error
return errors.Wrap(err, "failed to render upgrade template")
}
tmpDir := os.TempDir()
timeId := time.Now().Unix()
filePath := filesystem.JoinPaths(tmpDir, fmt.Sprintf("upgrade-%d.yml", timeId))
fileName := fmt.Sprintf("upgrade-%d.yml", timeId)
r := bytes.NewReader([]byte(composeFile))
err = filesystem.CreateFile(filePath, r)
filePath, err := service.fileService.StoreStackFileFromBytes("upgrade", fileName, []byte(composeFile))
if err != nil {
return errors.Wrap(err, "failed to create upgrade compose file")
}
@ -66,42 +63,37 @@ func (service *service) upgradeDocker(licenseKey, version, envType string) error
projectName := fmt.Sprintf(
"portainer-upgrade-%d-%s",
timeId,
strings.ReplaceAll(version, ".", "-"))
err = service.composeDeployer.Deploy(
ctx,
[]string{filePath},
libstack.DeployOptions{
ForceRecreate: true,
AbortOnContainerExit: true,
Options: libstack.Options{
ProjectName: projectName,
},
},
strings.ReplaceAll(version, ".", "-"),
)
// optimally, server was restarted by the updater, so we should not reach this point
tempStack := &portainer.Stack{
Name: projectName,
ProjectPath: filePath,
EntryPoint: fileName,
}
err = service.dockerComposeStackManager.Run(ctx, tempStack, environment, "updater", portainer.ComposeRunOptions{
Remove: true,
Detached: true,
})
if err != nil {
return errors.Wrap(err, "failed to deploy upgrade stack")
}
return errors.New("upgrade failed: server should have been restarted by the updater")
return nil
}
func (service *service) checkImageForDocker(ctx context.Context, image string, skipPullImage bool) error {
cli, err := client.NewClientWithOpts(
client.FromEnv,
client.WithAPIVersionNegotiation(),
)
func (service *service) checkImageForDocker(ctx context.Context, environment *portainer.Endpoint, imageName string, skipPullImage bool) error {
cli, err := service.dockerClientFactory.CreateClient(environment, "", nil)
if err != nil {
return errors.Wrap(err, "failed to create docker client")
}
if skipPullImage {
filters := filters.NewArgs()
filters.Add("reference", image)
images, err := cli.ImageList(ctx, types.ImageListOptions{
filters.Add("reference", imageName)
images, err := cli.ImageList(ctx, image.ListOptions{
Filters: filters,
})
if err != nil {
@ -109,15 +101,15 @@ func (service *service) checkImageForDocker(ctx context.Context, image string, s
}
if len(images) == 0 {
return errors.Errorf("image %s not found locally", image)
return errors.Errorf("image %s not found locally", imageName)
}
return nil
} else {
// check if available on registry
_, err := cli.DistributionInspect(ctx, image, "")
_, err := cli.DistributionInspect(ctx, imageName, "")
if err != nil {
return errors.Errorf("image %s not found on registry", image)
return errors.Errorf("image %s not found on registry", imageName)
}
return nil