Merge pull request #35721 from dnephin/fix-swagger-spec-errors
Fix codegen problems in swagger spec
diff --git a/api/swagger.yaml b/api/swagger.yaml
index 406b72a..7a5017f 100644
--- a/api/swagger.yaml
+++ b/api/swagger.yaml
@@ -7256,6 +7256,9 @@
User:
type: "string"
description: "The user, and optionally, group to run the exec process inside the container. Format is one of: `user`, `user:group`, `uid`, or `uid:gid`."
+ WorkingDir:
+ type: "string"
+ description: "The working directory for the exec process inside the container."
example:
AttachStdin: false
AttachStdout: true
diff --git a/api/types/configs.go b/api/types/configs.go
index 20c19f2..54d3e39 100644
--- a/api/types/configs.go
+++ b/api/types/configs.go
@@ -50,6 +50,7 @@
Detach bool // Execute in detach mode
DetachKeys string // Escape keys for detach
Env []string // Environment variables
+ WorkingDir string // Working directory
Cmd []string // Execution commands and args
}
diff --git a/daemon/exec.go b/daemon/exec.go
index 01670fa..83b7de2 100644
--- a/daemon/exec.go
+++ b/daemon/exec.go
@@ -122,6 +122,7 @@
execConfig.Tty = config.Tty
execConfig.Privileged = config.Privileged
execConfig.User = config.User
+ execConfig.WorkingDir = config.WorkingDir
linkedEnv, err := d.setupLinkedContainers(cntr)
if err != nil {
@@ -131,6 +132,9 @@
if len(execConfig.User) == 0 {
execConfig.User = cntr.Config.User
}
+ if len(execConfig.WorkingDir) == 0 {
+ execConfig.WorkingDir = cntr.Config.WorkingDir
+ }
d.registerExecCommand(cntr, execConfig)
@@ -211,7 +215,7 @@
Args: append([]string{ec.Entrypoint}, ec.Args...),
Env: ec.Env,
Terminal: ec.Tty,
- Cwd: c.Config.WorkingDir,
+ Cwd: ec.WorkingDir,
}
if p.Cwd == "" {
p.Cwd = "/"
diff --git a/daemon/exec/exec.go b/daemon/exec/exec.go
index 193d32f..370b403 100644
--- a/daemon/exec/exec.go
+++ b/daemon/exec/exec.go
@@ -31,6 +31,7 @@
Tty bool
Privileged bool
User string
+ WorkingDir string
Env []string
Pid int
}
diff --git a/daemon/graphdriver/lcow/lcow.go b/daemon/graphdriver/lcow/lcow.go
index 5ec8b8b..058c69f 100644
--- a/daemon/graphdriver/lcow/lcow.go
+++ b/daemon/graphdriver/lcow/lcow.go
@@ -824,7 +824,7 @@
return 0, fmt.Errorf("lcowdriver: applydiff: svm failed to boot: %s", err)
}
- // TODO @jhowardmsft - the retries are temporary to overcome platform reliablity issues.
+ // TODO @jhowardmsft - the retries are temporary to overcome platform reliability issues.
// Obviously this will be removed as platform bugs are fixed.
retries := 0
for {
diff --git a/distribution/errors.go b/distribution/errors.go
index dd6ff0a..355e9da 100644
--- a/distribution/errors.go
+++ b/distribution/errors.go
@@ -126,21 +126,25 @@
// continueOnError returns true if we should fallback to the next endpoint
// as a result of this error.
-func continueOnError(err error) bool {
+func continueOnError(err error, mirrorEndpoint bool) bool {
switch v := err.(type) {
case errcode.Errors:
if len(v) == 0 {
return true
}
- return continueOnError(v[0])
+ return continueOnError(v[0], mirrorEndpoint)
case ErrNoSupport:
- return continueOnError(v.Err)
+ return continueOnError(v.Err, mirrorEndpoint)
case errcode.Error:
- return shouldV2Fallback(v)
+ return mirrorEndpoint || shouldV2Fallback(v)
case *client.UnexpectedHTTPResponseError:
return true
case ImageConfigPullError:
- return false
+ // ImageConfigPullError only happens with v2 images, v1 fallback is
+ // unnecessary.
+ // Failures from a mirror endpoint should result in fallback to the
+ // canonical repo.
+ return mirrorEndpoint
case error:
return !strings.Contains(err.Error(), strings.ToLower(syscall.ESRCH.Error()))
}
diff --git a/distribution/errors_test.go b/distribution/errors_test.go
new file mode 100644
index 0000000..aa9ef4f
--- /dev/null
+++ b/distribution/errors_test.go
@@ -0,0 +1,85 @@
+package distribution
+
+import (
+ "errors"
+ "strings"
+ "syscall"
+ "testing"
+
+ "github.com/docker/distribution/registry/api/errcode"
+ "github.com/docker/distribution/registry/api/v2"
+ "github.com/docker/distribution/registry/client"
+)
+
+var alwaysContinue = []error{
+ &client.UnexpectedHTTPResponseError{},
+
+ // Some errcode.Errors that don't disprove the existence of a V1 image
+ errcode.Error{Code: errcode.ErrorCodeUnauthorized},
+ errcode.Error{Code: v2.ErrorCodeManifestUnknown},
+ errcode.Error{Code: v2.ErrorCodeNameUnknown},
+
+ errors.New("some totally unexpected error"),
+}
+
+var continueFromMirrorEndpoint = []error{
+ ImageConfigPullError{},
+
+ // Some other errcode.Error that doesn't indicate we should search for a V1 image.
+ errcode.Error{Code: errcode.ErrorCodeTooManyRequests},
+}
+
+var neverContinue = []error{
+ errors.New(strings.ToLower(syscall.ESRCH.Error())), // No such process
+}
+
+func TestContinueOnError_NonMirrorEndpoint(t *testing.T) {
+ for _, err := range alwaysContinue {
+ if !continueOnError(err, false) {
+ t.Errorf("Should continue from non-mirror endpoint: %T: '%s'", err, err.Error())
+ }
+ }
+
+ for _, err := range continueFromMirrorEndpoint {
+ if continueOnError(err, false) {
+ t.Errorf("Should only continue from mirror endpoint: %T: '%s'", err, err.Error())
+ }
+ }
+}
+
+func TestContinueOnError_MirrorEndpoint(t *testing.T) {
+ errs := []error{}
+ errs = append(errs, alwaysContinue...)
+ errs = append(errs, continueFromMirrorEndpoint...)
+ for _, err := range errs {
+ if !continueOnError(err, true) {
+ t.Errorf("Should continue from mirror endpoint: %T: '%s'", err, err.Error())
+ }
+ }
+}
+
+func TestContinueOnError_NeverContinue(t *testing.T) {
+ for _, isMirrorEndpoint := range []bool{true, false} {
+ for _, err := range neverContinue {
+ if continueOnError(err, isMirrorEndpoint) {
+ t.Errorf("Should never continue: %T: '%s'", err, err.Error())
+ }
+ }
+ }
+}
+
+func TestContinueOnError_UnnestsErrors(t *testing.T) {
+ // ContinueOnError should evaluate nested errcode.Errors.
+
+ // Assumes that v2.ErrorCodeNameUnknown is a continueable error code.
+ err := errcode.Errors{errcode.Error{Code: v2.ErrorCodeNameUnknown}}
+ if !continueOnError(err, false) {
+ t.Fatal("ContinueOnError should unnest, base return value on errcode.Errors")
+ }
+
+ // Assumes that errcode.ErrorCodeTooManyRequests is not a V1-fallback indication
+ err = errcode.Errors{errcode.Error{Code: errcode.ErrorCodeTooManyRequests}}
+ if continueOnError(err, false) {
+ t.Fatal("ContinueOnError should unnest, base return value on errcode.Errors")
+ }
+}
diff --git a/distribution/pull_v2.go b/distribution/pull_v2.go
index c8d784c..35ff529 100644
--- a/distribution/pull_v2.go
+++ b/distribution/pull_v2.go
@@ -74,7 +74,7 @@
if _, ok := err.(fallbackError); ok {
return err
}
- if continueOnError(err) {
+ if continueOnError(err, p.endpoint.Mirror) {
return fallbackError{
err: err,
confirmedV2: p.confirmedV2,
diff --git a/distribution/push_v2.go b/distribution/push_v2.go
index 7ffce5b..2aecc18 100644
--- a/distribution/push_v2.go
+++ b/distribution/push_v2.go
@@ -67,7 +67,7 @@
}
if err = p.pushV2Repository(ctx); err != nil {
- if continueOnError(err) {
+ if continueOnError(err, p.endpoint.Mirror) {
return fallbackError{
err: err,
confirmedV2: p.pushState.confirmedV2,
diff --git a/docs/contributing/set-up-dev-env.md b/docs/contributing/set-up-dev-env.md
index acd6888..28bea5b 100644
--- a/docs/contributing/set-up-dev-env.md
+++ b/docs/contributing/set-up-dev-env.md
@@ -10,8 +10,7 @@
You use the `moby/moby` repository and its `Dockerfile` to create a Docker image,
run a Docker container, and develop code in the container.
-If you followed the procedures that <a href="/opensource/project/set-up-git/" target="_blank">
-set up Git for contributing</a>, you should have a fork of the `moby/moby`
+If you followed the procedures that [set up Git for contributing](./set-up-git.md), you should have a fork of the `moby/moby`
repository. You also created a branch called `dry-run-test`. In this section,
you continue working with your fork on this branch.
@@ -106,8 +105,7 @@
```
If you are following along with this guide, you created a `dry-run-test`
- branch when you <a href="/opensource/project/set-up-git/" target="_blank">
- set up Git for contributing</a>.
+ branch when you [set up Git for contributing](./set-up-git.md).
3. Ensure you are on your `dry-run-test` branch.
@@ -132,14 +130,14 @@
```none
Successfully built 3d872560918e
docker run --rm -i --privileged -e BUILDFLAGS -e KEEPBUNDLE -e DOCKER_BUILD_GOGC -e DOCKER_BUILD_PKGS -e DOCKER_CLIENTONLY -e DOCKER_DEBUG -e DOCKER_EXPERIMENTAL -e DOCKER_GITCOMMIT -e DOCKER_GRAPHDRIVER=devicemapper -e DOCKER_INCREMENTAL_BINARY -e DOCKER_REMAP_ROOT -e DOCKER_STORAGE_OPTS -e DOCKER_USERLANDPROXY -e TESTDIRS -e TESTFLAGS -e TIMEOUT -v "home/ubuntu/repos/docker/bundles:/go/src/github.com/moby/moby/bundles" -t "docker-dev:dry-run-test" bash
- root@f31fa223770f:/go/src/github.com/moby/moby#
+ root@f31fa223770f:/go/src/github.com/docker/docker#
```
At this point, your prompt reflects the container's BASH shell.
5. List the contents of the current directory (`/go/src/github.com/moby/moby`).
- You should see the image's source from the `/go/src/github.com/moby/moby`
+ You should see the image's source from the `/go/src/github.com/docker/docker`
directory.
![List example](images/list_example.png)
@@ -147,7 +145,7 @@
6. Make a `dockerd` binary.
```none
- root@a8b2885ab900:/go/src/github.com/moby/moby# hack/make.sh binary
+ root@a8b2885ab900:/go/src/github.com/docker/docker# hack/make.sh binary
Removing bundles/
---> Making bundle: binary (in bundles/binary)
@@ -161,7 +159,7 @@
`/usr/local/bin/` directory.
```none
- root@a8b2885ab900:/go/src/github.com/moby/moby# make install
+ root@a8b2885ab900:/go/src/github.com/docker/docker# make install
```
8. Start the Engine daemon running in the background.
@@ -190,7 +188,7 @@
9. Inside your container, check your Docker version.
```none
- root@5f8630b873fe:/go/src/github.com/moby/moby# docker --version
+ root@5f8630b873fe:/go/src/github.com/docker/docker# docker --version
Docker version 1.12.0-dev, build 6e728fb
```
@@ -201,13 +199,13 @@
10. Run the `hello-world` image.
```none
- root@5f8630b873fe:/go/src/github.com/moby/moby# docker run hello-world
+ root@5f8630b873fe:/go/src/github.com/docker/docker# docker run hello-world
```
11. List the image you just downloaded.
```none
- root@5f8630b873fe:/go/src/github.com/moby/moby# docker images
+ root@5f8630b873fe:/go/src/github.com/docker/docker# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest c54a2cc56cbb 3 months ago 1.85 kB
```
@@ -296,7 +294,7 @@
10. To view your change, run the `dockerd --help` command in the docker development container shell.
```bash
- root@b0cb4f22715d:/go/src/github.com/moby/moby# dockerd --help
+ root@b0cb4f22715d:/go/src/github.com/docker/docker# dockerd --help
Usage: dockerd COMMAND
diff --git a/integration/container/exec_test.go b/integration/container/exec_test.go
new file mode 100644
index 0000000..22d7ec0
--- /dev/null
+++ b/integration/container/exec_test.go
@@ -0,0 +1,60 @@
+package container
+
+import (
+ "context"
+ "io/ioutil"
+ "testing"
+
+ "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/api/types/network"
+ "github.com/docker/docker/api/types/strslice"
+ "github.com/docker/docker/integration/util/request"
+ "github.com/stretchr/testify/require"
+)
+
+func TestExec(t *testing.T) {
+ defer setupTest(t)()
+ ctx := context.Background()
+ client := request.NewAPIClient(t)
+
+ container, err := client.ContainerCreate(ctx,
+ &container.Config{
+ Image: "busybox",
+ Tty: true,
+ WorkingDir: "/root",
+ Cmd: strslice.StrSlice([]string{"top"}),
+ },
+ &container.HostConfig{},
+ &network.NetworkingConfig{},
+ "foo",
+ )
+ require.NoError(t, err)
+ err = client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{})
+ require.NoError(t, err)
+
+ id, err := client.ContainerExecCreate(ctx, container.ID,
+ types.ExecConfig{
+ WorkingDir: "/tmp",
+ Env: strslice.StrSlice([]string{"FOO=BAR"}),
+ AttachStdout: true,
+ Cmd: strslice.StrSlice([]string{"sh", "-c", "env"}),
+ },
+ )
+ require.NoError(t, err)
+
+ resp, err := client.ContainerExecAttach(ctx, id.ID,
+ types.ExecStartCheck{
+ Detach: false,
+ Tty: false,
+ },
+ )
+ require.NoError(t, err)
+ defer resp.Close()
+ r, err := ioutil.ReadAll(resp.Reader)
+ require.NoError(t, err)
+ out := string(r)
+ require.NoError(t, err)
+ require.Contains(t, out, "PWD=/tmp", "exec command not running in expected /tmp working directory")
+ require.Contains(t, out, "FOO=BAR", "exec command not running with expected environment variable FOO")
+}