1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15: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,14 +1,7 @@
package platform
import (
"context"
"os"
dockerclient "github.com/portainer/portainer/api/docker/client"
"github.com/docker/docker/client"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)
const (
@ -20,6 +13,8 @@ const (
type ContainerPlatform string
const (
// PlatformDocker represent the Docker platform (Unknown)
PlatformDocker = ContainerPlatform("Docker")
// PlatformDockerStandalone represent the Docker platform (Standalone)
PlatformDockerStandalone = ContainerPlatform("Docker Standalone")
// PlatformDockerSwarm represent the Docker platform (Swarm)
@ -34,43 +29,22 @@ const (
// or KUBERNETES_SERVICE_HOST environment variable to determine if
// the container is running on Podman or inside the Kubernetes platform.
// Defaults to Docker otherwise.
func DetermineContainerPlatform() (ContainerPlatform, error) {
func DetermineContainerPlatform() ContainerPlatform {
podmanModeEnvVar := os.Getenv(PodmanMode)
if podmanModeEnvVar == "1" {
return PlatformPodman, nil
return PlatformPodman
}
serviceHostKubernetesEnvVar := os.Getenv(KubernetesServiceHost)
if serviceHostKubernetesEnvVar != "" {
return PlatformKubernetes, nil
return PlatformKubernetes
}
if !isRunningInContainer() {
return "", nil
return ""
}
dockerCli, err := dockerclient.CreateSimpleClient()
if err != nil {
return "", errors.WithMessage(err, "failed to create docker client")
}
defer dockerCli.Close()
info, err := dockerCli.Info(context.Background())
if err != nil {
if client.IsErrConnectionFailed(err) {
log.Warn().Err(err).Msg("failed to retrieve docker info")
return "", nil
}
return "", errors.WithMessage(err, "failed to retrieve docker info")
}
if info.Swarm.NodeID == "" {
return PlatformDockerStandalone, nil
}
return PlatformDockerSwarm, nil
return PlatformDocker
}
// isRunningInContainer returns true if the process is running inside a container

113
api/platform/service.go Normal file
View file

@ -0,0 +1,113 @@
package platform
import (
"errors"
"fmt"
"slices"
"strings"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/internal/endpointutils"
"github.com/rs/zerolog/log"
)
type Service interface {
GetLocalEnvironment() (*portainer.Endpoint, error)
GetPlatform() (ContainerPlatform, error)
}
type service struct {
dataStore dataservices.DataStore
environment *portainer.Endpoint
platform ContainerPlatform
}
func NewService(dataStore dataservices.DataStore) (Service, error) {
return &service{
dataStore: dataStore,
}, nil
}
func (service *service) GetLocalEnvironment() (*portainer.Endpoint, error) {
if service.environment == nil {
environment, platform, err := guessLocalEnvironment(service.dataStore)
if err != nil {
return nil, err
}
service.environment = environment
service.platform = platform
}
return service.environment, nil
}
func (service *service) GetPlatform() (ContainerPlatform, error) {
if service.environment == nil {
environment, platform, err := guessLocalEnvironment(service.dataStore)
if err != nil {
return "", err
}
service.environment = environment
service.platform = platform
}
return service.platform, nil
}
var platformToEndpointType = map[ContainerPlatform][]portainer.EndpointType{
PlatformDocker: {portainer.AgentOnDockerEnvironment, portainer.DockerEnvironment},
PlatformKubernetes: {portainer.KubernetesLocalEnvironment},
}
func guessLocalEnvironment(dataStore dataservices.DataStore) (*portainer.Endpoint, ContainerPlatform, error) {
platform := DetermineContainerPlatform()
if !slices.Contains([]ContainerPlatform{PlatformDocker, PlatformKubernetes}, platform) {
log.Debug().
Str("platform", string(platform)).
Msg("environment not supported for upgrade")
return nil, "", nil
}
endpoints, err := dataStore.Endpoint().Endpoints()
if err != nil {
return nil, "", fmt.Errorf("failed to retrieve endpoints: %w", err)
}
endpointTypes, ok := platformToEndpointType[platform]
if !ok {
return nil, "", errors.New("failed to determine endpoint type")
}
for _, endpoint := range endpoints {
if slices.Contains(endpointTypes, endpoint.Type) {
if platform != PlatformDocker {
return &endpoint, platform, nil
}
dockerPlatform := checkDockerEnvTypeForUpgrade(&endpoint)
if dockerPlatform != "" {
return &endpoint, dockerPlatform, nil
}
}
}
return nil, "", errors.New("failed to find local endpoint")
}
func checkDockerEnvTypeForUpgrade(environment *portainer.Endpoint) ContainerPlatform {
if endpointutils.IsLocalEndpoint(environment) { // standalone
return PlatformDockerStandalone
}
if strings.HasPrefix(environment.URL, "tcp://tasks.") { // swarm
return PlatformDockerSwarm
}
return ""
}