1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 20:35:25 +02:00

feat(libstack): remove the docker-compose binary BE-10801 (#111)

Co-authored-by: andres-portainer <andres-portainer@users.noreply.github.com>
Co-authored-by: oscarzhou <oscar.zhou@portainer.io>
This commit is contained in:
andres-portainer 2024-11-11 19:05:56 -03:00 committed by GitHub
parent 55aa0c0c5d
commit a7127bc74f
34 changed files with 913 additions and 761 deletions

View file

@ -433,10 +433,7 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
dockerConfigPath := fileService.GetDockerConfigPath()
composeDeployer, err := compose.NewComposeDeployer(*flags.Assets, dockerConfigPath)
if err != nil {
log.Fatal().Err(err).Msg("failed initializing compose deployer")
}
composeDeployer := compose.NewComposeDeployer()
composeStackManager := initComposeStackManager(composeDeployer, proxyManager)

View file

@ -108,9 +108,11 @@ func (manager *ComposeStackManager) Down(ctx context.Context, stack *portainer.S
defer proxy.Close()
}
err = manager.deployer.Remove(ctx, stack.Name, nil, libstack.Options{
WorkingDir: "",
Host: url,
err = manager.deployer.Remove(ctx, stack.Name, nil, libstack.RemoveOptions{
Options: libstack.Options{
WorkingDir: "",
Host: url,
},
})
return errors.Wrap(err, "failed to remove a stack")
@ -185,7 +187,7 @@ func createEnvFile(stack *portainer.Stack) (string, error) {
return "", err
}
return "stack.env", nil
return envFilePath, nil
}
// copyDefaultEnvFile copies the default .env file if it exists to the provided writer

View file

@ -42,15 +42,11 @@ func setup(t *testing.T) (*portainer.Stack, *portainer.Endpoint) {
}
func Test_UpAndDown(t *testing.T) {
testhelpers.IntegrationTest(t)
stack, endpoint := setup(t)
deployer, err := compose.NewComposeDeployer("", "")
if err != nil {
t.Fatal(err)
}
deployer := compose.NewComposeDeployer()
w, err := NewComposeStackManager(deployer, nil)
if err != nil {

View file

@ -4,6 +4,7 @@ import (
"io"
"os"
"path"
"path/filepath"
"testing"
portainer "github.com/portainer/portainer/api"
@ -53,7 +54,7 @@ func Test_createEnvFile(t *testing.T) {
result, _ := createEnvFile(tt.stack)
if tt.expected != "" {
assert.Equal(t, "stack.env", result)
assert.Equal(t, filepath.Join(tt.stack.ProjectPath, "stack.env"), result)
f, _ := os.Open(path.Join(dir, "stack.env"))
content, _ := io.ReadAll(f)
@ -77,7 +78,7 @@ func Test_createEnvFile_mergesDefultAndInplaceEnvVars(t *testing.T) {
},
}
result, err := createEnvFile(stack)
assert.Equal(t, "stack.env", result)
assert.Equal(t, filepath.Join(stack.ProjectPath, "stack.env"), result)
assert.NoError(t, err)
assert.FileExists(t, path.Join(dir, "stack.env"))
f, _ := os.Open(path.Join(dir, "stack.env"))

View file

@ -56,8 +56,7 @@ func (handler *Handler) stackMigrate(w http.ResponseWriter, r *http.Request) *ht
}
var payload stackMigratePayload
err = request.DecodeAndValidateJSONPayload(r, &payload)
if err != nil {
if err := request.DecodeAndValidateJSONPayload(r, &payload); err != nil {
return httperror.BadRequest("Invalid request payload", err)
}
@ -79,8 +78,7 @@ func (handler *Handler) stackMigrate(w http.ResponseWriter, r *http.Request) *ht
return httperror.InternalServerError("Unable to find an endpoint with the specified identifier inside the database", err)
}
err = handler.requestBouncer.AuthorizedEndpointOperation(r, endpoint)
if err != nil {
if err := handler.requestBouncer.AuthorizedEndpointOperation(r, endpoint); err != nil {
return httperror.Forbidden("Permission denied to access endpoint", err)
}
@ -156,14 +154,12 @@ func (handler *Handler) stackMigrate(w http.ResponseWriter, r *http.Request) *ht
newName := stack.Name
stack.Name = oldName
err = handler.deleteStack(securityContext.UserID, stack, endpoint)
if err != nil {
if err := handler.deleteStack(securityContext.UserID, stack, endpoint); err != nil {
return httperror.InternalServerError(err.Error(), err)
}
stack.Name = newName
err = handler.DataStore.Stack().Update(stack.ID, stack)
if err != nil {
if err := handler.DataStore.Stack().Update(stack.ID, stack); err != nil {
return httperror.InternalServerError("Unable to persist the stack changes inside the database", err)
}
@ -210,10 +206,10 @@ func (handler *Handler) migrateComposeStack(r *http.Request, stack *portainer.St
}
// Deploy the stack
err = composeDeploymentConfig.Deploy()
if err != nil {
if err := composeDeploymentConfig.Deploy(); err != nil {
return httperror.InternalServerError(err.Error(), err)
}
return nil
}
@ -237,8 +233,7 @@ func (handler *Handler) migrateSwarmStack(r *http.Request, stack *portainer.Stac
}
// Deploy the stack
err = swarmDeploymentConfig.Deploy()
if err != nil {
if err := swarmDeploymentConfig.Deploy(); err != nil {
return httperror.InternalServerError(err.Error(), err)
}

View file

@ -197,17 +197,14 @@ func (handler *Handler) deployStack(r *http.Request, stack *portainer.Stack, pul
switch stack.Type {
case portainer.DockerSwarmStack:
prune := false
if stack.Option != nil {
prune = stack.Option.Prune
}
// Create swarm deployment config
securityContext, err := security.RetrieveRestrictedRequestContext(r)
if err != nil {
return httperror.InternalServerError("Unable to retrieve info from request context", err)
}
prune := stack.Option != nil && stack.Option.Prune
deploymentConfiger, err = deployments.CreateSwarmStackDeploymentConfig(securityContext, stack, endpoint, handler.DataStore, handler.FileService, handler.StackDeployer, prune, pullImage)
if err != nil {
return httperror.InternalServerError(err.Error(), err)

View file

@ -1375,6 +1375,7 @@ type (
//
// When this is set, docker compose will output its logs to stdout
AbortOnContainerExit bool
Prune bool
}
ComposeRunOptions struct {

View file

@ -76,11 +76,11 @@ vJUUCFYm8+9p6gTVOcoMit+eGSwa81PCPEs1TnU1PV/PaDFeUhn/mg==
type noopDeployer struct{}
// without unpacker
func (s *noopDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune bool, pullImage bool) error {
func (s *noopDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune, pullImage bool) error {
return nil
}
func (s *noopDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forcePullImage bool, forceRecreate bool) error {
func (s *noopDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forcePullImage, forceRecreate bool) error {
return nil
}
@ -89,7 +89,7 @@ func (s *noopDeployer) DeployKubernetesStack(stack *portainer.Stack, endpoint *p
}
// with unpacker
func (s *noopDeployer) DeployRemoteComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forcePullImage bool, forceRecreate bool) error {
func (s *noopDeployer) DeployRemoteComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forcePullImage, forceRecreate bool) error {
return nil
}
func (s *noopDeployer) UndeployRemoteComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
@ -101,7 +101,7 @@ func (s *noopDeployer) StartRemoteComposeStack(stack *portainer.Stack, endpoint
func (s *noopDeployer) StopRemoteComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
return nil
}
func (s *noopDeployer) DeployRemoteSwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune bool, pullImage bool) error {
func (s *noopDeployer) DeployRemoteSwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune, pullImage bool) error {
return nil
}
func (s *noopDeployer) UndeployRemoteSwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint) error {

View file

@ -4,17 +4,17 @@ import (
"context"
"sync"
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
dockerclient "github.com/portainer/portainer/api/docker/client"
k "github.com/portainer/portainer/api/kubernetes"
"github.com/pkg/errors"
)
type BaseStackDeployer interface {
DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune bool, pullImage bool) error
DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forcePullImage bool, forceRecreate bool) error
DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune, pullImage bool) error
DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forcePullImage, forceRecreate bool) error
DeployKubernetesStack(stack *portainer.Stack, endpoint *portainer.Endpoint, user *portainer.User) error
}
@ -44,7 +44,7 @@ func NewStackDeployer(swarmStackManager portainer.SwarmStackManager, composeStac
dataStore: dataStore,
}
}
func (d *stackDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune bool, pullImage bool) error {
func (d *stackDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, prune, pullImage bool) error {
d.lock.Lock()
defer d.lock.Unlock()
@ -54,7 +54,7 @@ func (d *stackDeployer) DeploySwarmStack(stack *portainer.Stack, endpoint *porta
return d.swarmStackManager.Deploy(stack, prune, pullImage, endpoint)
}
func (d *stackDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forcePullImage bool, forceRecreate bool) error {
func (d *stackDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *portainer.Endpoint, registries []portainer.Registry, forcePullImage, forceRecreate bool) error {
d.lock.Lock()
defer d.lock.Unlock()
@ -63,8 +63,7 @@ func (d *stackDeployer) DeployComposeStack(stack *portainer.Stack, endpoint *por
// --force-recreate doesn't pull updated images
if forcePullImage {
err := d.composeStackManager.Pull(context.TODO(), stack, endpoint)
if err != nil {
if err := d.composeStackManager.Pull(context.TODO(), stack, endpoint); err != nil {
return err
}
}
@ -99,8 +98,7 @@ func (d *stackDeployer) DeployKubernetesStack(stack *portainer.Stack, endpoint *
return errors.Wrap(err, "failed to create temp kub deployment files")
}
err = k8sDeploymentConfig.Deploy()
if err != nil {
if err := k8sDeploymentConfig.Deploy(); err != nil {
return errors.Wrap(err, "failed to deploy kubernetes application")
}

View file

@ -3,13 +3,13 @@ package deployments
import (
"fmt"
"github.com/rs/zerolog/log"
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/stacks/stackutils"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)
type ComposeStackDeploymentConfig struct {
@ -25,7 +25,6 @@ type ComposeStackDeploymentConfig struct {
}
func CreateComposeStackDeploymentConfig(securityContext *security.RestrictedRequestContext, stack *portainer.Stack, endpoint *portainer.Endpoint, dataStore dataservices.DataStore, fileService portainer.FileService, deployer StackDeployer, forcePullImage, forceCreate bool) (*ComposeStackDeploymentConfig, error) {
user, err := dataStore.User().Read(securityContext.UserID)
if err != nil {
return nil, fmt.Errorf("unable to load user information from the database: %w", err)
@ -81,11 +80,11 @@ func (config *ComposeStackDeploymentConfig) Deploy() error {
!securitySettings.AllowContainerCapabilitiesForRegularUsers) &&
!isAdminOrEndpointAdmin {
err = stackutils.ValidateStackFiles(config.stack, securitySettings, config.FileService)
if err != nil {
if err := stackutils.ValidateStackFiles(config.stack, securitySettings, config.FileService); err != nil {
return err
}
}
if stackutils.IsRelativePathStack(config.stack) {
return config.StackDeployer.DeployRemoteComposeStack(config.stack, config.endpoint, config.registries, config.forcePullImage, config.ForceCreate)
}