Merge component 'engine' from git@github.com:moby/moby master
This commit is contained in:
@ -52,6 +52,7 @@ RUN apt-get update && apt-get install -y \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libdevmapper-dev \
|
||||
libnet-dev \
|
||||
libnl-3-dev \
|
||||
libprotobuf-c0-dev \
|
||||
libprotobuf-dev \
|
||||
@ -94,11 +95,9 @@ ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# Install CRIU for checkpoint/restore support
|
||||
ENV CRIU_VERSION 2.12.1
|
||||
# Install dependancy packages specific to criu
|
||||
RUN apt-get install libnet-dev -y && \
|
||||
mkdir -p /usr/src/criu \
|
||||
&& curl -sSL https://github.com/xemul/criu/archive/v${CRIU_VERSION}.tar.gz | tar -v -C /usr/src/criu/ -xz --strip-components=1 \
|
||||
ENV CRIU_VERSION 3.6
|
||||
RUN mkdir -p /usr/src/criu \
|
||||
&& curl -sSL https://github.com/checkpoint-restore/criu/archive/v${CRIU_VERSION}.tar.gz | tar -C /usr/src/criu/ -xz --strip-components=1 \
|
||||
&& cd /usr/src/criu \
|
||||
&& make \
|
||||
&& make install-criu
|
||||
|
||||
@ -7259,6 +7259,9 @@ paths:
|
||||
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
|
||||
|
||||
@ -50,6 +50,7 @@ type ExecConfig struct {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@ -122,6 +122,7 @@ func (d *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (str
|
||||
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 @@ func (d *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (str
|
||||
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 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R
|
||||
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 = "/"
|
||||
|
||||
@ -31,6 +31,7 @@ type Config struct {
|
||||
Tty bool
|
||||
Privileged bool
|
||||
User string
|
||||
WorkingDir string
|
||||
Env []string
|
||||
Pid int
|
||||
}
|
||||
|
||||
@ -824,7 +824,7 @@ func (d *Driver) ApplyDiff(id, parent string, diff io.Reader) (int64, error) {
|
||||
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 {
|
||||
|
||||
@ -126,21 +126,25 @@ func TranslatePullError(err error, ref reference.Named) error {
|
||||
|
||||
// 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()))
|
||||
}
|
||||
|
||||
85
components/engine/distribution/errors_test.go
Normal file
85
components/engine/distribution/errors_test.go
Normal file
@ -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")
|
||||
}
|
||||
}
|
||||
@ -74,7 +74,7 @@ func (p *v2Puller) Pull(ctx context.Context, ref reference.Named, platform strin
|
||||
if _, ok := err.(fallbackError); ok {
|
||||
return err
|
||||
}
|
||||
if continueOnError(err) {
|
||||
if continueOnError(err, p.endpoint.Mirror) {
|
||||
return fallbackError{
|
||||
err: err,
|
||||
confirmedV2: p.confirmedV2,
|
||||
|
||||
@ -67,7 +67,7 @@ func (p *v2Pusher) Push(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
if err = p.pushV2Repository(ctx); err != nil {
|
||||
if continueOnError(err) {
|
||||
if continueOnError(err, p.endpoint.Mirror) {
|
||||
return fallbackError{
|
||||
err: err,
|
||||
confirmedV2: p.pushState.confirmedV2,
|
||||
|
||||
@ -132,14 +132,14 @@ can take over 15 minutes to complete.
|
||||
```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.
|
||||
|
||||

|
||||
@ -147,7 +147,7 @@ can take over 15 minutes to complete.
|
||||
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 +161,7 @@ can take over 15 minutes to complete.
|
||||
`/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 +190,7 @@ can take over 15 minutes to complete.
|
||||
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 +201,13 @@ can take over 15 minutes to complete.
|
||||
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 +296,7 @@ example, you'll edit the help for the `attach` subcommand.
|
||||
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
|
||||
|
||||
|
||||
60
components/engine/integration/container/exec_test.go
Normal file
60
components/engine/integration/container/exec_test.go
Normal file
@ -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")
|
||||
}
|
||||
Reference in New Issue
Block a user