Skip to content
This repository was archived by the owner on Jun 26, 2023. It is now read-only.

Commit 915b021

Browse files
authored
feat: return exit code of failed deploys [EE-4615] (#28)
1 parent 96e5dce commit 915b021

File tree

7 files changed

+110
-39
lines changed

7 files changed

+110
-39
lines changed

compose/compose.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import (
55
"github.com/portainer/docker-compose-wrapper/compose/internal/composeplugin"
66
)
77

8-
// NewComposeDeployer will try to create a wrapper for docker-compose binary
9-
// if it's not availbale it will try to create a wrapper for docker-compose plugin
8+
// NewComposeDeployer will try to create a wrapper for docker-compose plugin
109
func NewComposeDeployer(binaryPath, configPath string) (libstack.Deployer, error) {
1110
return composeplugin.NewPluginWrapper(binaryPath, configPath)
1211
}

compose/compose_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strings"
1212
"testing"
1313

14+
libstack "github.com/portainer/docker-compose-wrapper"
1415
"github.com/portainer/docker-compose-wrapper/compose"
1516
)
1617

@@ -57,7 +58,7 @@ func Test_UpAndDown(t *testing.T) {
5758

5859
ctx := context.Background()
5960

60-
err = deployer.Deploy(ctx, "", "", "", []string{filePathOriginal, filePathOverride}, "", false)
61+
err = deployer.Deploy(ctx, []string{filePathOriginal, filePathOverride}, libstack.DeployOptions{})
6162
if err != nil {
6263
t.Fatal(err)
6364
}
@@ -66,7 +67,7 @@ func Test_UpAndDown(t *testing.T) {
6667
t.Fatal("container should exist")
6768
}
6869

69-
err = deployer.Remove(ctx, "", "", "", []string{filePathOriginal, filePathOverride}, "")
70+
err = deployer.Remove(ctx, []string{filePathOriginal, filePathOverride}, libstack.Options{})
7071
if err != nil {
7172
t.Fatal(err)
7273
}

compose/internal/composeplugin/composeplugin.go

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ package composeplugin
33
import (
44
"bytes"
55
"context"
6-
"log"
76
"os"
87
"os/exec"
98
"strings"
109

1110
"github.com/pkg/errors"
1211
libstack "github.com/portainer/docker-compose-wrapper"
1312
"github.com/portainer/docker-compose-wrapper/compose/internal/utils"
13+
"github.com/rs/zerolog/log"
1414
)
1515

1616
var (
@@ -33,64 +33,81 @@ func NewPluginWrapper(binaryPath, configPath string) (libstack.Deployer, error)
3333
}
3434

3535
// Up create and start containers
36-
func (wrapper *PluginWrapper) Deploy(ctx context.Context, workingDir, host, projectName string, filePaths []string, envFilePath string, forceRecreate bool) error {
37-
output, err := wrapper.command(newUpCommand(filePaths, forceRecreate), workingDir, host, projectName, envFilePath)
36+
func (wrapper *PluginWrapper) Deploy(ctx context.Context, filePaths []string, options libstack.DeployOptions) error {
37+
output, err := wrapper.command(newUpCommand(filePaths, upOptions{
38+
forceRecreate: options.ForceRecreate,
39+
abortOnContainerExit: options.AbortOnContainerExit,
40+
}), options.Options,
41+
)
3842
if len(output) != 0 {
3943
if err != nil {
4044
return err
4145
}
4246

43-
log.Printf("[INFO] [docker compose] [message: Stack deployment successful]")
44-
log.Printf("[DEBUG] [docker compose] [output: %s]", output)
47+
log.Info().
48+
Str("message", "Stack deployment successful")
49+
50+
log.Debug().
51+
Str("output", string(output)).
52+
Msg("docker compose")
4553
}
4654

4755
return err
4856
}
4957

5058
// Down stop and remove containers
51-
func (wrapper *PluginWrapper) Remove(ctx context.Context, workingDir, host, projectName string, filePaths []string, envFilePath string) error {
52-
output, err := wrapper.command(newDownCommand(filePaths), workingDir, host, projectName, envFilePath)
59+
func (wrapper *PluginWrapper) Remove(ctx context.Context, filePaths []string, options libstack.Options) error {
60+
output, err := wrapper.command(newDownCommand(filePaths), options)
5361
if len(output) != 0 {
5462
if err != nil {
5563
return err
5664
}
5765

58-
log.Printf("[INFO] [docker compose] [message: Stack removal successful]")
59-
log.Printf("[DEBUG] [docker compose] [output: %s]", output)
66+
log.Info().
67+
Str("message", "Stack removal successful")
68+
69+
log.Debug().
70+
Str("output", string(output)).
71+
Msg("docker compose")
72+
6073
}
6174

6275
return err
6376
}
6477

6578
// Pull images
66-
func (wrapper *PluginWrapper) Pull(ctx context.Context, workingDir, host, projectName string, filePaths []string, envFilePath string) error {
67-
output, err := wrapper.command(newPullCommand(filePaths), workingDir, host, projectName, envFilePath)
79+
func (wrapper *PluginWrapper) Pull(ctx context.Context, filePaths []string, options libstack.Options) error {
80+
output, err := wrapper.command(newPullCommand(filePaths), options)
6881
if len(output) != 0 {
6982
if err != nil {
7083
return err
7184
}
7285

73-
log.Printf("[INFO] [docker compose] [message: Stack pull successful]")
74-
log.Printf("[DEBUG] [docker compose] [output: %s]", output)
86+
log.Info().
87+
Str("message", "Stack pull successful")
88+
89+
log.Debug().
90+
Str("output", string(output)).
91+
Msg("docker compose")
7592
}
7693

7794
return err
7895
}
7996

8097
// Command execute a docker-compose command
81-
func (wrapper *PluginWrapper) command(command composeCommand, workingDir, host, projectName, envFilePath string) ([]byte, error) {
98+
func (wrapper *PluginWrapper) command(command composeCommand, options libstack.Options) ([]byte, error) {
8299
program := utils.ProgramPath(wrapper.binaryPath, "docker-compose")
83100

84-
if projectName != "" {
85-
command.WithProjectName(projectName)
101+
if options.ProjectName != "" {
102+
command.WithProjectName(options.ProjectName)
86103
}
87104

88-
if envFilePath != "" {
89-
command.WithEnvFilePath(envFilePath)
105+
if options.EnvFilePath != "" {
106+
command.WithEnvFilePath(options.EnvFilePath)
90107
}
91108

92-
if host != "" {
93-
command.WithHost(host)
109+
if options.Host != "" {
110+
command.WithHost(options.Host)
94111
}
95112

96113
var stderr bytes.Buffer
@@ -99,20 +116,26 @@ func (wrapper *PluginWrapper) command(command composeCommand, workingDir, host,
99116
args = append(args, command.ToArgs()...)
100117

101118
cmd := exec.Command(program, args...)
102-
cmd.Dir = workingDir
119+
cmd.Dir = options.WorkingDir
103120

104121
if wrapper.configPath != "" {
105-
if wrapper.configPath != "" {
106-
cmd.Env = os.Environ()
107-
cmd.Env = append(cmd.Env, "DOCKER_CONFIG="+wrapper.configPath)
108-
}
122+
cmd.Env = os.Environ()
123+
cmd.Env = append(cmd.Env, "DOCKER_CONFIG="+wrapper.configPath)
109124
}
110125

111126
cmd.Stderr = &stderr
112127

113128
output, err := cmd.Output()
114129
if err != nil {
115-
return nil, errors.New(stderr.String())
130+
errOutput := stderr.String()
131+
log.Warn().
132+
Str("output", string(output)).
133+
Str("error_output", errOutput).
134+
Err(err).
135+
Msg("docker compose command failed")
136+
137+
// stderr output outputs useless information such as "Removing network stack_default"
138+
return nil, errors.WithMessage(err, "docker-compose command failed")
116139
}
117140

118141
return output, nil
@@ -135,9 +158,21 @@ func newCommand(command []string, filePaths []string) composeCommand {
135158
}
136159
}
137160

138-
func newUpCommand(filePaths []string, forceRereate bool) composeCommand {
139-
args := []string{"up", "-d"}
140-
if forceRereate {
161+
type upOptions struct {
162+
forceRecreate bool
163+
abortOnContainerExit bool ``
164+
}
165+
166+
func newUpCommand(filePaths []string, options upOptions) composeCommand {
167+
args := []string{"up"}
168+
169+
if options.abortOnContainerExit {
170+
args = append(args, "--abort-on-container-exit")
171+
} else { // detach by default, not working with --abort-on-container-exit
172+
args = append(args, "-d")
173+
}
174+
175+
if options.forceRecreate {
141176
args = append(args, "--force-recreate")
142177
}
143178
return newCommand(args, filePaths)

compose/internal/composeplugin/composeplugin_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ services:
9292
}
9393

9494
ctx := context.Background()
95-
err = w.Deploy(ctx, "", "", "", []string{filePathOriginal, filePathOverride}, "", false)
95+
err = w.Deploy(ctx, []string{filePathOriginal, filePathOverride}, libstack.DeployOptions{})
9696
if err != nil {
9797
t.Fatal(err)
9898
}
@@ -101,7 +101,7 @@ services:
101101
t.Fatal("container should exist")
102102
}
103103

104-
err = w.Remove(ctx, "", "", "", []string{filePathOriginal, filePathOverride}, "")
104+
err = w.Remove(ctx, []string{filePathOriginal, filePathOverride}, libstack.Options{})
105105
if err != nil {
106106
t.Fatal(err)
107107
}

go.mod

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
module github.com/portainer/docker-compose-wrapper
22

3-
go 1.16
3+
go 1.19
44

55
require github.com/pkg/errors v0.9.1
6+
7+
require (
8+
github.com/mattn/go-colorable v0.1.12 // indirect
9+
github.com/mattn/go-isatty v0.0.14 // indirect
10+
github.com/rs/zerolog v1.28.0 // indirect
11+
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
12+
)

go.sum

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,14 @@
1+
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
2+
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
3+
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
4+
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
5+
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
6+
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
17
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
28
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
9+
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
10+
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
11+
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
12+
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
13+
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
14+
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

libstack.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,24 @@ import (
55
)
66

77
type Deployer interface {
8-
Deploy(ctx context.Context, workingDir, host, projectName string, filePaths []string, envFilePath string, forceRecreate bool) error
9-
Remove(ctx context.Context, workingDir, host, projectName string, filePaths []string, envFilePath string) error
10-
Pull(ctx context.Context, workingDir, host, projectName string, filePaths []string, envFilePath string) error
8+
Deploy(ctx context.Context, filePaths []string, options DeployOptions) error
9+
Remove(ctx context.Context, filePaths []string, options Options) error
10+
Pull(ctx context.Context, filePaths []string, options Options) error
11+
}
12+
13+
type Options struct {
14+
WorkingDir string
15+
Host string
16+
ProjectName string
17+
EnvFilePath string
18+
}
19+
20+
type DeployOptions struct {
21+
Options
22+
ForceRecreate bool
23+
// AbortOnContainerExit will stop the deployment if a container exits.
24+
// This is useful when running a onetime task.
25+
//
26+
// When this is set, docker compose will output its logs to stdout
27+
AbortOnContainerExit bool ``
1128
}

0 commit comments

Comments
 (0)