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

Commit 832651b

Browse files
authored
Merge pull request #157 from docker/kill_child_process_on_cancel
Kill child process "docker-classic" on cancel
2 parents c8acbc3 + ea98a2d commit 832651b

File tree

4 files changed

+63
-5
lines changed

4 files changed

+63
-5
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ lint: ## run linter(s)
6666
--target lint
6767

6868
classic-link: ## create docker-classic symlink if does not already exist
69-
ln -s /usr/local/bin/docker-classic /Applications/Docker.app/Contents/Resources/bin/docker
69+
ln -s /Applications/Docker.app/Contents/Resources/bin/docker /usr/local/bin/docker-classic
7070

7171
help: ## Show help
7272
@echo Please specify a build target. The choices are:

cli/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func execMoby(ctx context.Context) {
186186
// Only run original docker command if the current context is not
187187
// ours.
188188
if err != nil {
189-
cmd := exec.Command("docker-classic", os.Args[1:]...)
189+
cmd := exec.CommandContext(ctx, "docker-classic", os.Args[1:]...)
190190
cmd.Stdin = os.Stdin
191191
cmd.Stdout = os.Stdout
192192
cmd.Stderr = os.Stderr

tests/e2e/e2e_test.go

+36-2
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,20 @@ package main
2929

3030
import (
3131
"fmt"
32+
"io/ioutil"
33+
"log"
3234
"os"
3335
"os/exec"
3436
"path/filepath"
37+
"strings"
3538
"testing"
3639
"time"
3740

38-
"gotest.tools/golden"
39-
4041
. "github.com/onsi/gomega"
4142
"github.com/stretchr/testify/suite"
4243

44+
"gotest.tools/golden"
45+
4346
. "github.com/docker/api/tests/framework"
4447
)
4548

@@ -79,6 +82,37 @@ func (s *E2eSuite) TestSetupError() {
7982
})
8083
}
8184

85+
func (s *E2eSuite) TestKillChildOnCancel() {
86+
It("should kill docker-classic if parent command is cancelled", func() {
87+
out := s.NewCommand("ps", "-x").ExecOrDie()
88+
Expect(out).NotTo(ContainSubstring("docker-classic"))
89+
90+
dir := s.ConfigDir
91+
Expect(ioutil.WriteFile(filepath.Join(dir, "Dockerfile"), []byte(`FROM alpine:3.10
92+
RUN sleep 100`), 0644)).To(Succeed())
93+
shutdown := make(chan time.Time)
94+
errs := make(chan error)
95+
ctx := s.NewDockerCommand("build", "--no-cache", "-t", "test-sleep-image", ".").WithinDirectory(dir).WithTimeout(shutdown)
96+
go func() {
97+
_, err := ctx.Exec()
98+
errs <- err
99+
}()
100+
err := WaitFor(time.Second, 3*time.Second, errs, func() bool {
101+
out := s.NewCommand("ps", "-x").ExecOrDie()
102+
return strings.Contains(out, "docker-classic")
103+
})
104+
Expect(err).NotTo(HaveOccurred())
105+
log.Println("Killing docker process")
106+
107+
close(shutdown)
108+
err = WaitFor(time.Second, 4*time.Second, nil, func() bool {
109+
out := s.NewCommand("ps", "-x").ExecOrDie()
110+
return !strings.Contains(out, "docker-classic")
111+
})
112+
Expect(err).NotTo(HaveOccurred())
113+
})
114+
}
115+
82116
func (s *E2eSuite) TestLegacy() {
83117
It("should list all legacy commands", func() {
84118
output := s.NewDockerCommand("--help").ExecOrDie()

tests/framework/exec.go

+25-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"io"
3434
"os/exec"
3535
"strings"
36+
"syscall"
3637
"time"
3738

3839
"github.com/onsi/gomega"
@@ -129,6 +130,29 @@ func (b CmdContext) Exec() (string, error) {
129130
}
130131
}
131132

133+
//WaitFor waits for a condition to be true
134+
func WaitFor(interval, duration time.Duration, abort <-chan error, condition func() bool) error {
135+
ticker := time.NewTicker(interval)
136+
defer ticker.Stop()
137+
timeout := make(chan int)
138+
go func() {
139+
time.Sleep(duration)
140+
close(timeout)
141+
}()
142+
for {
143+
select {
144+
case err := <-abort:
145+
return err
146+
case <-timeout:
147+
return fmt.Errorf("timeout after %v", duration)
148+
case <-ticker.C:
149+
if condition() {
150+
return nil
151+
}
152+
}
153+
}
154+
}
155+
132156
// Execute executes a command.
133157
// The command cannot be re-used afterwards.
134158
func Execute(cmd *exec.Cmd, timeout <-chan time.Time) (string, error) {
@@ -152,7 +176,7 @@ func Execute(cmd *exec.Cmd, timeout <-chan time.Time) (string, error) {
152176
}
153177
case <-timeout:
154178
log.Debugf("%s %s timed-out", cmd.Path, strings.Join(cmd.Args[1:], " "))
155-
if err := cmd.Process.Kill(); err != nil {
179+
if err := cmd.Process.Signal(syscall.SIGTERM); err != nil {
156180
return "", err
157181
}
158182
return "", fmt.Errorf(

0 commit comments

Comments
 (0)