Skip to content

Commit 002a481

Browse files
committed
add support of env variables to exec/run/local jobs and refactor tests
1 parent 126a526 commit 002a481

9 files changed

+178
-80
lines changed

cli/config_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -257,12 +257,12 @@ func (s *SuiteConfig) TestLabelsConfig(c *C) {
257257
"some": {
258258
requiredLabel: "true",
259259
serviceLabel: "true",
260-
labelPrefix + "." + jobRun + ".job1.schedule": "schedule1",
261-
labelPrefix + "." + jobRun + ".job1.command": "command1",
262-
labelPrefix + "." + jobRun + ".job1.env": "KEY1=value1",
263-
labelPrefix + "." + jobRun + ".job2.schedule": "schedule2",
264-
labelPrefix + "." + jobRun + ".job2.command": "command2",
265-
labelPrefix + "." + jobRun + ".job2.env": `["KEY1=value1", "KEY2=value2"]`,
260+
labelPrefix + "." + jobRun + ".job1.schedule": "schedule1",
261+
labelPrefix + "." + jobRun + ".job1.command": "command1",
262+
labelPrefix + "." + jobRun + ".job1.environment": "KEY1=value1",
263+
labelPrefix + "." + jobRun + ".job2.schedule": "schedule2",
264+
labelPrefix + "." + jobRun + ".job2.command": "command2",
265+
labelPrefix + "." + jobRun + ".job2.environment": `["KEY1=value1", "KEY2=value2"]`,
266266
},
267267
},
268268
ExpectedConfig: Config{
@@ -271,14 +271,14 @@ func (s *SuiteConfig) TestLabelsConfig(c *C) {
271271
Schedule: "schedule1",
272272
Command: "command1",
273273
},
274-
Env: []string{"KEY1=value1"},
274+
Environment: []string{"KEY1=value1"},
275275
},
276276
},
277277
"job2": {RunJob: core.RunJob{BareJob: core.BareJob{
278278
Schedule: "schedule2",
279279
Command: "command2",
280280
},
281-
Env: []string{"KEY1=value1", "KEY2=value2"},
281+
Environment: []string{"KEY1=value1", "KEY2=value2"},
282282
},
283283
},
284284
},

cli/docker-labels.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ func setJobParam(params map[string]interface{}, paramName, paramVal string) {
161161
params[paramName] = arr
162162
return
163163
}
164-
case "env":
164+
case "environment":
165165
arr := []string{} // allow providing JSON arr of env keyvalues
166166
if err := json.Unmarshal([]byte(paramVal), &arr); err == nil {
167167
params[paramName] = arr

core/execjob.go

+33-20
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ import (
88
)
99

1010
type ExecJob struct {
11-
BareJob `mapstructure:",squash"`
12-
Client *docker.Client `json:"-"`
13-
Container string
14-
User string `default:"root"`
15-
TTY bool `default:"false"`
11+
BareJob `mapstructure:",squash"`
12+
Client *docker.Client `json:"-"`
13+
Container string
14+
User string `default:"root"`
15+
TTY bool `default:"false"`
16+
Environment []string
17+
18+
execID string
1619
}
1720

1821
func NewExecJob(c *docker.Client) *ExecJob {
@@ -25,11 +28,27 @@ func (j *ExecJob) Run(ctx *Context) error {
2528
return err
2629
}
2730

28-
if err := j.startExec(ctx.Execution, exec); err != nil {
31+
if exec != nil {
32+
j.execID = exec.ID
33+
}
34+
35+
if err := j.startExec(ctx.Execution); err != nil {
2936
return err
3037
}
3138

32-
return j.inspectExec(exec)
39+
inspect, err := j.inspectExec()
40+
if err != nil {
41+
return err
42+
}
43+
44+
switch inspect.ExitCode {
45+
case 0:
46+
return nil
47+
case -1:
48+
return ErrUnexpected
49+
default:
50+
return fmt.Errorf("error non-zero exit code: %d", inspect.ExitCode)
51+
}
3352
}
3453

3554
func (j *ExecJob) buildExec() (*docker.Exec, error) {
@@ -41,6 +60,7 @@ func (j *ExecJob) buildExec() (*docker.Exec, error) {
4160
Cmd: args.GetArgs(j.Command),
4261
Container: j.Container,
4362
User: j.User,
63+
Env: j.Environment,
4464
})
4565

4666
if err != nil {
@@ -50,8 +70,8 @@ func (j *ExecJob) buildExec() (*docker.Exec, error) {
5070
return exec, nil
5171
}
5272

53-
func (j *ExecJob) startExec(e *Execution, exec *docker.Exec) error {
54-
err := j.Client.StartExec(exec.ID, docker.StartExecOptions{
73+
func (j *ExecJob) startExec(e *Execution) error {
74+
err := j.Client.StartExec(j.execID, docker.StartExecOptions{
5575
Tty: j.TTY,
5676
OutputStream: e.OutputStream,
5777
ErrorStream: e.ErrorStream,
@@ -65,19 +85,12 @@ func (j *ExecJob) startExec(e *Execution, exec *docker.Exec) error {
6585
return nil
6686
}
6787

68-
func (j *ExecJob) inspectExec(exec *docker.Exec) error {
69-
i, err := j.Client.InspectExec(exec.ID)
88+
func (j *ExecJob) inspectExec() (*docker.ExecInspect, error) {
89+
i, err := j.Client.InspectExec(j.execID)
7090

7191
if err != nil {
72-
return fmt.Errorf("error inspecting exec: %s", err)
92+
return i, fmt.Errorf("error inspecting exec: %s", err)
7393
}
7494

75-
switch i.ExitCode {
76-
case 0:
77-
return nil
78-
case -1:
79-
return ErrUnexpected
80-
default:
81-
return fmt.Errorf("error non-zero exit code: %d", i.ExitCode)
82-
}
95+
return i, nil
8396
}

core/execjob_test.go

+29-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ package core
33
import (
44
"archive/tar"
55
"bytes"
6+
"encoding/json"
7+
"net/http"
68

7-
"github.com/fsouza/go-dockerclient"
9+
docker "github.com/fsouza/go-dockerclient"
810
"github.com/fsouza/go-dockerclient/testing"
911
. "gopkg.in/check.v1"
1012
)
@@ -18,11 +20,33 @@ type SuiteExecJob struct {
1820

1921
var _ = Suite(&SuiteExecJob{})
2022

23+
// overwrite version handler, because
24+
// exec configuration Env is only supported in API#1.25 and above
25+
// https://github.com/fsouza/go-dockerclient/blob/0f57349a7248b9b35ad2193ffe70953d5893e2b8/testing/server.go#L1607
26+
func versionDockerHandler(w http.ResponseWriter, r *http.Request) {
27+
envs := map[string]interface{}{
28+
"Version": "1.10.1",
29+
"Os": "linux",
30+
"KernelVersion": "3.13.0-77-generic",
31+
"GoVersion": "go1.17.1",
32+
"GitCommit": "9e83765",
33+
"Arch": "amd64",
34+
"ApiVersion": "1.27",
35+
"BuildTime": "2015-12-01T07:09:13.444803460+00:00",
36+
"Experimental": false,
37+
}
38+
w.WriteHeader(http.StatusOK)
39+
json.NewEncoder(w).Encode(envs)
40+
41+
}
42+
2143
func (s *SuiteExecJob) SetUpTest(c *C) {
2244
var err error
2345
s.server, err = testing.NewServer("127.0.0.1:0", nil, nil)
2446
c.Assert(err, IsNil)
2547

48+
s.server.CustomHandler("/version", http.HandlerFunc(versionDockerHandler))
49+
2650
s.client, err = docker.NewClient(s.server.URL())
2751
c.Assert(err, IsNil)
2852

@@ -38,6 +62,7 @@ func (s *SuiteExecJob) TestRun(c *C) {
3862
job := &ExecJob{Client: s.client}
3963
job.Container = ContainerFixture
4064
job.Command = `echo -a "foo bar"`
65+
job.Environment = []string{"test_Key1=value1", "test_Key2=value2"}
4166
job.User = "foo"
4267
job.TTY = true
4368

@@ -49,13 +74,15 @@ func (s *SuiteExecJob) TestRun(c *C) {
4974

5075
container, err := s.client.InspectContainer(ContainerFixture)
5176
c.Assert(err, IsNil)
77+
c.Assert(len(container.ExecIDs) > 0, Equals, true)
5278

53-
exec, err := s.client.InspectExec(container.ExecIDs[0])
79+
exec, err := job.inspectExec()
5480
c.Assert(err, IsNil)
5581
c.Assert(exec.ProcessConfig.EntryPoint, Equals, "echo")
5682
c.Assert(exec.ProcessConfig.Arguments, DeepEquals, []string{"-a", "foo bar"})
5783
c.Assert(exec.ProcessConfig.User, Equals, "foo")
5884
c.Assert(exec.ProcessConfig.Tty, Equals, true)
85+
// no way to check for env :|
5986
}
6087

6188
func (s *SuiteExecJob) buildContainer(c *C) {

core/localjob.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package core
22

33
import (
4+
"os"
45
"os/exec"
56

67
"github.com/gobs/args"
@@ -37,7 +38,9 @@ func (j *LocalJob) buildCommand(ctx *Context) (*exec.Cmd, error) {
3738
Args: args,
3839
Stdout: ctx.Execution.OutputStream,
3940
Stderr: ctx.Execution.ErrorStream,
40-
Env: j.Environment,
41-
Dir: j.Dir,
41+
// add custom env variables to the existing ones
42+
// instead of overwriting them
43+
Env: append(os.Environ(), j.Environment...),
44+
Dir: j.Dir,
4245
}, nil
4346
}

core/localjob_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package core
22

33
import (
4+
"strings"
5+
46
"github.com/armon/circbuf"
57

68
. "gopkg.in/check.v1"
@@ -22,3 +24,29 @@ func (s *SuiteLocalJob) TestRun(c *C) {
2224
c.Assert(err, IsNil)
2325
c.Assert(b.String(), Equals, "foo bar\n")
2426
}
27+
28+
func (s *SuiteLocalJob) TestEnvironment(c *C) {
29+
job := &LocalJob{}
30+
job.Command = `env`
31+
env := []string{"test_Key1=value1", "test_Key2=value2"}
32+
job.Environment = env
33+
34+
b, _ := circbuf.NewBuffer(1000)
35+
e := NewExecution()
36+
e.OutputStream = b
37+
38+
err := job.Run(&Context{Execution: e})
39+
c.Assert(err, IsNil)
40+
41+
// check that expected keys are present in the system env
42+
for _, expectedEnv := range env {
43+
found := false
44+
for _, systemEnv := range strings.Split(strings.TrimSuffix(b.String(), "\n"), "\n") {
45+
if expectedEnv == systemEnv {
46+
found = true
47+
break
48+
}
49+
}
50+
c.Assert(found, Equals, true)
51+
}
52+
}

core/runjob.go

+36-25
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@ type RunJob struct {
2929
Delete string `default:"true"`
3030
Pull string `default:"true"`
3131

32-
Image string
33-
Network string
34-
Container string
35-
Volume []string
36-
Env []string
32+
Image string
33+
Network string
34+
Container string
35+
Volume []string
36+
Environment []string
37+
38+
containerID string
3739
}
3840

3941
func NewRunJob(c *docker.Client) *RunJob {
@@ -92,18 +94,31 @@ func (j *RunJob) Run(ctx *Context) error {
9294
return err
9395
}
9496
} else {
95-
container, err = j.getContainer(j.Container)
97+
container, err = j.Client.InspectContainer(j.Container)
9698
if err != nil {
9799
return err
98100
}
99101
}
100102

103+
if container != nil {
104+
j.containerID = container.ID
105+
}
106+
107+
// cleanup container if it is a created one
108+
if j.Container == "" {
109+
defer func() {
110+
if delErr := j.deleteContainer(); delErr != nil {
111+
ctx.Warn("failed to delete container: " + delErr.Error())
112+
}
113+
}()
114+
}
115+
101116
startTime := time.Now()
102-
if err := j.startContainer(ctx.Execution, container); err != nil {
117+
if err := j.startContainer(); err != nil {
103118
return err
104119
}
105120

106-
err = j.watchContainer(container.ID)
121+
err = j.watchContainer()
107122
if err == ErrUnexpected {
108123
return err
109124
}
@@ -120,14 +135,6 @@ func (j *RunJob) Run(ctx *Context) error {
120135
ctx.Warn("failed to fetch container logs: " + logsErr.Error())
121136
}
122137

123-
if j.Container == "" {
124-
defer func() {
125-
if delErr := j.deleteContainer(container.ID); delErr != nil {
126-
ctx.Warn("failed to delete container: " + delErr.Error())
127-
}
128-
}()
129-
}
130-
131138
return err
132139
}
133140

@@ -163,7 +170,7 @@ func (j *RunJob) buildContainer() (*docker.Container, error) {
163170
Tty: j.TTY,
164171
Cmd: args.GetArgs(j.Command),
165172
User: j.User,
166-
Env: j.Env,
173+
Env: j.Environment,
167174
},
168175
NetworkingConfig: &docker.NetworkingConfig{},
169176
HostConfig: &docker.HostConfig{
@@ -193,12 +200,16 @@ func (j *RunJob) buildContainer() (*docker.Container, error) {
193200
return c, nil
194201
}
195202

196-
func (j *RunJob) startContainer(e *Execution, c *docker.Container) error {
197-
return j.Client.StartContainer(c.ID, &docker.HostConfig{})
203+
func (j *RunJob) startContainer() error {
204+
return j.Client.StartContainer(j.containerID, &docker.HostConfig{})
205+
}
206+
207+
func (j *RunJob) stopContainer(timeout uint) error {
208+
return j.Client.StopContainer(j.containerID, timeout)
198209
}
199210

200-
func (j *RunJob) getContainer(id string) (*docker.Container, error) {
201-
container, err := j.Client.InspectContainer(id)
211+
func (j *RunJob) getContainer() (*docker.Container, error) {
212+
container, err := j.Client.InspectContainer(j.containerID)
202213
if err != nil {
203214
return nil, err
204215
}
@@ -210,7 +221,7 @@ const (
210221
maxProcessDuration = time.Hour * 24
211222
)
212223

213-
func (j *RunJob) watchContainer(containerID string) error {
224+
func (j *RunJob) watchContainer() error {
214225
var s docker.State
215226
var r time.Duration
216227
for {
@@ -221,7 +232,7 @@ func (j *RunJob) watchContainer(containerID string) error {
221232
return ErrMaxTimeRunning
222233
}
223234

224-
c, err := j.Client.InspectContainer(containerID)
235+
c, err := j.Client.InspectContainer(j.containerID)
225236
if err != nil {
226237
return err
227238
}
@@ -242,12 +253,12 @@ func (j *RunJob) watchContainer(containerID string) error {
242253
}
243254
}
244255

245-
func (j *RunJob) deleteContainer(containerID string) error {
256+
func (j *RunJob) deleteContainer() error {
246257
if delete, _ := strconv.ParseBool(j.Delete); !delete {
247258
return nil
248259
}
249260

250261
return j.Client.RemoveContainer(docker.RemoveContainerOptions{
251-
ID: containerID,
262+
ID: j.containerID,
252263
})
253264
}

0 commit comments

Comments
 (0)