mirror of https://github.com/portainer/portainer
fix(edgestacks): remove edge stacks even after a system crash or power-off BE-10822 (#208)
parent
a8147b9713
commit
473084e915
|
@ -49,7 +49,7 @@ func (kcl *KubeClient) fetchResourceQuotasForNonAdmin(namespace string) (*[]core
|
|||
func (kcl *KubeClient) fetchResourceQuotas(namespace string) (*[]corev1.ResourceQuota, error) {
|
||||
resourceQuotas, err := kcl.cli.CoreV1().ResourceQuotas(namespace).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("an error occured, failed to list resource quotas for the admin user: %w", err)
|
||||
return nil, fmt.Errorf("an error occurred, failed to list resource quotas for the admin user: %w", err)
|
||||
}
|
||||
|
||||
return &resourceQuotas.Items, nil
|
||||
|
|
|
@ -2,13 +2,16 @@ package compose
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/pkg/libstack"
|
||||
|
||||
"github.com/compose-spec/compose-go/v2/dotenv"
|
||||
|
@ -22,6 +25,8 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const PortainerEdgeStackLabel = "io.portainer.edge_stack_id"
|
||||
|
||||
var mu sync.Mutex
|
||||
|
||||
func withCli(
|
||||
|
@ -125,7 +130,7 @@ func withComposeService(
|
|||
// Deploy creates and starts containers
|
||||
func (c *ComposeDeployer) Deploy(ctx context.Context, filePaths []string, options libstack.DeployOptions) error {
|
||||
return withComposeService(ctx, filePaths, options.Options, func(composeService api.Service, project *types.Project) error {
|
||||
addServiceLabels(project, false)
|
||||
addServiceLabels(project, false, options.EdgeStackID)
|
||||
|
||||
project = project.WithoutUnnecessaryResources()
|
||||
|
||||
|
@ -154,7 +159,7 @@ func (c *ComposeDeployer) Deploy(ctx context.Context, filePaths []string, option
|
|||
// Run runs the given service just once, without considering dependencies
|
||||
func (c *ComposeDeployer) Run(ctx context.Context, filePaths []string, serviceName string, options libstack.RunOptions) error {
|
||||
return withComposeService(ctx, filePaths, options.Options, func(composeService api.Service, project *types.Project) error {
|
||||
addServiceLabels(project, true)
|
||||
addServiceLabels(project, true, 0)
|
||||
|
||||
for name, service := range project.Services {
|
||||
if name == serviceName {
|
||||
|
@ -242,7 +247,51 @@ func (c *ComposeDeployer) Config(ctx context.Context, filePaths []string, option
|
|||
return payload, nil
|
||||
}
|
||||
|
||||
func addServiceLabels(project *types.Project, oneOff bool) {
|
||||
func (c *ComposeDeployer) GetExistingEdgeStacks(ctx context.Context) ([]libstack.EdgeStack, error) {
|
||||
m := make(map[int]libstack.EdgeStack)
|
||||
|
||||
if err := withComposeService(ctx, nil, libstack.Options{}, func(composeService api.Service, project *types.Project) error {
|
||||
stacks, err := composeService.List(ctx, api.ListOptions{
|
||||
All: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, s := range stacks {
|
||||
summary, err := composeService.Ps(ctx, s.Name, api.PsOptions{All: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, cs := range summary {
|
||||
if sid, ok := cs.Labels[PortainerEdgeStackLabel]; ok {
|
||||
id, err := strconv.Atoi(sid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cs.Labels[api.ProjectLabel] == "" {
|
||||
return errors.New("invalid project label")
|
||||
}
|
||||
|
||||
m[id] = libstack.EdgeStack{
|
||||
ID: id,
|
||||
Name: cs.Labels[api.ProjectLabel],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return slices.Collect(maps.Values(m)), nil
|
||||
}
|
||||
|
||||
func addServiceLabels(project *types.Project, oneOff bool, edgeStackID portainer.EdgeStackID) {
|
||||
oneOffLabel := "False"
|
||||
if oneOff {
|
||||
oneOffLabel = "True"
|
||||
|
@ -257,6 +306,11 @@ func addServiceLabels(project *types.Project, oneOff bool) {
|
|||
api.ConfigFilesLabel: strings.Join(project.ComposeFiles, ","),
|
||||
api.OneoffLabel: oneOffLabel,
|
||||
}
|
||||
|
||||
if edgeStackID > 0 {
|
||||
s.CustomLabels.Add(PortainerEdgeStackLabel, strconv.Itoa(int(edgeStackID)))
|
||||
}
|
||||
|
||||
project.Services[i] = s
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package libstack
|
|||
import (
|
||||
"context"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
|
||||
configtypes "github.com/docker/cli/cli/config/types"
|
||||
)
|
||||
|
||||
|
@ -18,6 +20,7 @@ type Deployer interface {
|
|||
Validate(ctx context.Context, filePaths []string, options Options) error
|
||||
WaitForStatus(ctx context.Context, name string, status Status) <-chan WaitResult
|
||||
Config(ctx context.Context, filePaths []string, options Options) ([]byte, error)
|
||||
GetExistingEdgeStacks(ctx context.Context) ([]EdgeStack, error)
|
||||
}
|
||||
|
||||
type Status string
|
||||
|
@ -65,6 +68,7 @@ type DeployOptions struct {
|
|||
// When this is set, docker compose will output its logs to stdout
|
||||
AbortOnContainerExit bool
|
||||
RemoveOrphans bool
|
||||
EdgeStackID portainer.EdgeStackID
|
||||
}
|
||||
|
||||
type RunOptions struct {
|
||||
|
@ -82,3 +86,8 @@ type RemoveOptions struct {
|
|||
|
||||
Volumes bool
|
||||
}
|
||||
|
||||
type EdgeStack struct {
|
||||
ID int
|
||||
Name string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue