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:
parent
3cb484f06a
commit
6f84317e7a
22 changed files with 362 additions and 158 deletions
|
@ -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
113
api/platform/service.go
Normal 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 ""
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue