Merge component 'engine' from git@github.com:moby/moby master

This commit is contained in:
GordonTheTurtle
2018-03-23 17:06:08 +00:00
8 changed files with 236 additions and 22 deletions
+4 -12
View File
@@ -44,9 +44,7 @@ FROM base AS criu
# Install CRIU for checkpoint/restore support
ENV CRIU_VERSION 3.6
# Install dependancy packages specific to criu
RUN case $(uname -m) in \
x86_64) \
apt-get update && apt-get install -y \
RUN apt-get update && apt-get install -y \
libnet-dev \
libprotobuf-c0-dev \
libprotobuf-dev \
@@ -59,13 +57,7 @@ RUN case $(uname -m) in \
&& 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 PREFIX=/opt/criu install-criu ;\
;; \
armv7l|aarch64|ppc64le|s390x) \
mkdir -p /opt/criu; \
;; \
esac
&& make PREFIX=/opt/criu install-criu
FROM base AS registry
# Install two versions of the registry. The first is an older version that
@@ -80,8 +72,8 @@ RUN set -x \
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
&& case $(uname -m) in \
x86_64|ppc64le|s390x) \
&& case $(dpkg --print-architecture) in \
amd64|ppc64*|s390x) \
(cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1"); \
GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH"; \
go build -buildmode=pie -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry; \
+1 -1
View File
@@ -270,7 +270,7 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R
case <-attachErr:
// TERM signal worked
}
return fmt.Errorf("context cancelled")
return ctx.Err()
case err := <-attachErr:
if err != nil {
if _, ok := err.(term.EscapeError); !ok {
+19 -1
View File
@@ -15,6 +15,7 @@ import (
"github.com/docker/distribution/manifest/schema1"
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/distribution/reference"
"github.com/docker/distribution/registry/api/errcode"
"github.com/docker/distribution/registry/client"
apitypes "github.com/docker/docker/api/types"
"github.com/docker/docker/distribution/metadata"
@@ -55,12 +56,14 @@ type pushState struct {
// confirmedV2 is set to true if we confirm we're talking to a v2
// registry. This is used to limit fallbacks to the v1 protocol.
confirmedV2 bool
hasAuthInfo bool
}
func (p *v2Pusher) Push(ctx context.Context) (err error) {
p.pushState.remoteLayers = make(map[layer.DiffID]distribution.Descriptor)
p.repo, p.pushState.confirmedV2, err = NewV2Repository(ctx, p.repoInfo, p.endpoint, p.config.MetaHeaders, p.config.AuthConfig, "push", "pull")
p.pushState.hasAuthInfo = p.config.AuthConfig.RegistryToken != "" || (p.config.AuthConfig.Username != "" && p.config.AuthConfig.Password != "")
if err != nil {
logrus.Debugf("Error getting v2 registry: %v", err)
return err
@@ -308,6 +311,7 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
// Attempt to find another repository in the same registry to mount the layer from to avoid an unnecessary upload
candidates := getRepositoryMountCandidates(pd.repoInfo, pd.hmacKey, maxMountAttempts, v2Metadata)
isUnauthorizedError := false
for _, mountCandidate := range candidates {
logrus.Debugf("attempting to mount layer %s (%s) from %s", diffID, mountCandidate.Digest, mountCandidate.SourceRepository)
createOpts := []distribution.BlobCreateOption{}
@@ -360,11 +364,26 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
return distribution.Descriptor{}, xfer.DoNotRetry{Err: err}
}
return err.Descriptor, nil
case errcode.Errors:
for _, e := range err {
switch e := e.(type) {
case errcode.Error:
if e.Code == errcode.ErrorCodeUnauthorized {
// when unauthorized error that indicate user don't has right to push layer to register
logrus.Debugln("failed to push layer to registry because unauthorized error")
isUnauthorizedError = true
}
default:
}
}
default:
logrus.Infof("failed to mount layer %s (%s) from %s: %v", diffID, mountCandidate.Digest, mountCandidate.SourceRepository, err)
}
// when error is unauthorizedError and user don't hasAuthInfo that's the case user don't has right to push layer to register
// and he hasn't login either, in this case candidate cache should be removed
if len(mountCandidate.SourceRepository) > 0 &&
!(isUnauthorizedError && !pd.pushState.hasAuthInfo) &&
(metadata.CheckV2MetadataHMAC(&mountCandidate, pd.hmacKey) ||
len(mountCandidate.HMAC) == 0) {
cause := "blob mount failure"
@@ -398,7 +417,6 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
}
}
defer layerUpload.Close()
// upload the blob
return pd.uploadUsingSession(ctx, progressOutput, diffID, layerUpload)
}
@@ -2,6 +2,7 @@ package distribution // import "github.com/docker/docker/distribution"
import (
"net/http"
"net/url"
"reflect"
"testing"
@@ -9,9 +10,13 @@ import (
"github.com/docker/distribution/context"
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/distribution/reference"
"github.com/docker/distribution/registry/api/errcode"
"github.com/docker/docker/api/types"
"github.com/docker/docker/distribution/metadata"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/progress"
refstore "github.com/docker/docker/reference"
"github.com/docker/docker/registry"
"github.com/opencontainers/go-digest"
)
@@ -461,6 +466,158 @@ func TestLayerAlreadyExists(t *testing.T) {
}
}
type mockReferenceStore struct {
}
func (s *mockReferenceStore) References(id digest.Digest) []reference.Named {
return []reference.Named{}
}
func (s *mockReferenceStore) ReferencesByName(ref reference.Named) []refstore.Association {
return []refstore.Association{}
}
func (s *mockReferenceStore) AddTag(ref reference.Named, id digest.Digest, force bool) error {
return nil
}
func (s *mockReferenceStore) AddDigest(ref reference.Canonical, id digest.Digest, force bool) error {
return nil
}
func (s *mockReferenceStore) Delete(ref reference.Named) (bool, error) {
return true, nil
}
func (s *mockReferenceStore) Get(ref reference.Named) (digest.Digest, error) {
return "", nil
}
func TestWhenEmptyAuthConfig(t *testing.T) {
for _, authInfo := range []struct {
username string
password string
registryToken string
expected bool
}{
{
username: "",
password: "",
registryToken: "",
expected: false,
},
{
username: "username",
password: "password",
registryToken: "",
expected: true,
},
{
username: "",
password: "",
registryToken: "token",
expected: true,
},
} {
imagePushConfig := &ImagePushConfig{}
imagePushConfig.AuthConfig = &types.AuthConfig{
Username: authInfo.username,
Password: authInfo.password,
RegistryToken: authInfo.registryToken,
}
imagePushConfig.ReferenceStore = &mockReferenceStore{}
repoInfo, _ := reference.ParseNormalizedNamed("xujihui1985/test.img")
pusher := &v2Pusher{
config: imagePushConfig,
repoInfo: &registry.RepositoryInfo{
Name: repoInfo,
},
endpoint: registry.APIEndpoint{
URL: &url.URL{
Scheme: "https",
Host: "index.docker.io",
},
Version: registry.APIVersion1,
TrimHostname: true,
},
}
pusher.Push(context.Background())
if pusher.pushState.hasAuthInfo != authInfo.expected {
t.Errorf("hasAuthInfo does not match expected: %t != %t", authInfo.expected, pusher.pushState.hasAuthInfo)
}
}
}
type mockBlobStoreWithCreate struct {
mockBlobStore
repo *mockRepoWithBlob
}
func (blob *mockBlobStoreWithCreate) Create(ctx context.Context, options ...distribution.BlobCreateOption) (distribution.BlobWriter, error) {
return nil, errcode.Errors(append([]error{errcode.ErrorCodeUnauthorized.WithMessage("unauthorized")}))
}
type mockRepoWithBlob struct {
mockRepo
}
func (m *mockRepoWithBlob) Blobs(ctx context.Context) distribution.BlobStore {
blob := &mockBlobStoreWithCreate{}
blob.mockBlobStore.repo = &m.mockRepo
blob.repo = m
return blob
}
type mockMetadataService struct {
mockV2MetadataService
}
func (m *mockMetadataService) GetMetadata(diffID layer.DiffID) ([]metadata.V2Metadata, error) {
return []metadata.V2Metadata{
taggedMetadata("abcd", "sha256:ff3a5c916c92643ff77519ffa742d3ec61b7f591b6b7504599d95a4a41134e28", "docker.io/user/app1"),
taggedMetadata("abcd", "sha256:ff3a5c916c92643ff77519ffa742d3ec61b7f591b6b7504599d95a4a41134e22", "docker.io/user/app/base"),
taggedMetadata("hash", "sha256:ff3a5c916c92643ff77519ffa742d3ec61b7f591b6b7504599d95a4a41134e23", "docker.io/user/app"),
taggedMetadata("abcd", "sha256:ff3a5c916c92643ff77519ffa742d3ec61b7f591b6b7504599d95a4a41134e24", "127.0.0.1/user/app"),
taggedMetadata("hash", "sha256:ff3a5c916c92643ff77519ffa742d3ec61b7f591b6b7504599d95a4a41134e25", "docker.io/user/foo"),
taggedMetadata("hash", "sha256:ff3a5c916c92643ff77519ffa742d3ec61b7f591b6b7504599d95a4a41134e26", "docker.io/app/bar"),
}, nil
}
var removeMetadata bool
func (m *mockMetadataService) Remove(metadata metadata.V2Metadata) error {
removeMetadata = true
return nil
}
func TestPushRegistryWhenAuthInfoEmpty(t *testing.T) {
repoInfo, _ := reference.ParseNormalizedNamed("user/app")
ms := &mockMetadataService{}
remoteErrors := map[digest.Digest]error{digest.Digest("sha256:apple"): distribution.ErrAccessDenied}
remoteBlobs := map[digest.Digest]distribution.Descriptor{digest.Digest("sha256:apple"): {Digest: digest.Digest("shar256:apple")}}
repo := &mockRepoWithBlob{
mockRepo: mockRepo{
t: t,
errors: remoteErrors,
blobs: remoteBlobs,
requests: []string{},
},
}
pd := &v2PushDescriptor{
hmacKey: []byte("abcd"),
repoInfo: repoInfo,
layer: &storeLayer{
Layer: layer.EmptyLayer,
},
repo: repo,
v2MetadataService: ms,
pushState: &pushState{
remoteLayers: make(map[layer.DiffID]distribution.Descriptor),
hasAuthInfo: false,
},
checkedDigests: make(map[digest.Digest]struct{}),
}
pd.Upload(context.Background(), &progressSink{t})
if removeMetadata {
t.Fatalf("expect remove not be called but called")
}
}
func taggedMetadata(key string, dgst string, sourceRepo string) metadata.V2Metadata {
meta := metadata.V2Metadata{
Digest: digest.Digest(dgst),
+46
View File
@@ -0,0 +1,46 @@
# Docker Image Specification v1.
This directory contains documents about Docker Image Specification v1.X.
The v1 file layout and manifests are no longer used in Moby and Docker, except in `docker save` and `docker load`.
However, v1 Image JSON (`application/vnd.docker.container.image.v1+json`) has been still widely
used and officially adopted in [V2 manifest](https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-2.md)
and in [OCI Image Format Specification](https://github.com/opencontainers/image-spec).
## v1.X rough Changelog
All 1.X versions are compatible with older ones.
### [v1.2](v1.2.md)
* Implemented in Docker v1.12 (July, 2016)
* The official spec document was written in August 2016 ([#25750](https://github.com/moby/moby/pull/25750))
Changes:
* `Healthcheck` struct was added to Image JSON
### [v1.1](v1.1.md)
* Implemented in Docker v1.10 (February, 2016)
* The official spec document was written in April 2016 ([#22264](https://github.com/moby/moby/pull/22264))
Changes:
* IDs were made into SHA256 digest values rather than random values
* Layer directory names were made into deterministic values rather than random ID values
* `manifest.json` was added
### [v1](v1.md)
* The initial revision
* The official spec document was written in late 2014 ([#9560](https://github.com/moby/moby/pull/9560)), but actual implementations had existed even earlier
## Related specifications
* [Open Containers Initiative (OCI) Image Format Specification v1.0.0](https://github.com/opencontainers/image-spec/tree/v1.0.0)
* [Docker Image Manifest Version 2, Schema 2](https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-2.md)
* [Docker Image Manifest Version 2, Schema 1](https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-1.md) (*DEPRECATED*)
* [Docker Registry HTTP API V2](https://docs.docker.com/registry/spec/api/)
@@ -22,7 +22,7 @@ func TestInspectCpusetInConfigPre120(t *testing.T) {
client := request.NewAPIClient(t, client.WithVersion("1.19"))
ctx := context.Background()
name := "cpusetinconfig-pre120"
name := "cpusetinconfig-pre120-" + t.Name()
// Create container with up to-date-API
container.Run(t, ctx, request.NewAPIClient(t), container.WithName(name),
container.WithCmd("true"),
@@ -17,9 +17,10 @@ func TestPsFilter(t *testing.T) {
client := request.NewAPIClient(t)
ctx := context.Background()
prev := container.Create(t, ctx, client, container.WithName("prev"))
container.Create(t, ctx, client, container.WithName("top"))
next := container.Create(t, ctx, client, container.WithName("next"))
prev := container.Create(t, ctx, client, container.WithName("prev-"+t.Name()))
topContainerName := "top-" + t.Name()
container.Create(t, ctx, client, container.WithName(topContainerName))
next := container.Create(t, ctx, client, container.WithName("next-"+t.Name()))
containerIDs := func(containers []types.Container) []string {
entries := []string{}
@@ -30,7 +31,7 @@ func TestPsFilter(t *testing.T) {
}
f1 := filters.NewArgs()
f1.Add("since", "top")
f1.Add("since", topContainerName)
q1, err := client.ContainerList(ctx, types.ContainerListOptions{
All: true,
Filters: f1,
@@ -39,7 +40,7 @@ func TestPsFilter(t *testing.T) {
assert.Check(t, is.Contains(containerIDs(q1), next))
f2 := filters.NewArgs()
f2.Add("before", "top")
f2.Add("before", topContainerName)
q2, err := client.ContainerList(ctx, types.ContainerListOptions{
All: true,
Filters: f2,
@@ -21,7 +21,7 @@ func TestStopContainerWithRestartPolicyAlways(t *testing.T) {
client := request.NewAPIClient(t)
ctx := context.Background()
names := []string{"verifyRestart1", "verifyRestart2"}
names := []string{"verifyRestart1-" + t.Name(), "verifyRestart2-" + t.Name()}
for _, name := range names {
container.Run(t, ctx, client, container.WithName(name), container.WithCmd("false"), func(c *container.TestContainerConfig) {
c.HostConfig.RestartPolicy.Name = "always"
@@ -49,7 +49,7 @@ func TestDeleteDevicemapper(t *testing.T) {
client := request.NewAPIClient(t)
ctx := context.Background()
id := container.Run(t, ctx, client, container.WithName("foo"), container.WithCmd("echo"))
id := container.Run(t, ctx, client, container.WithName("foo-"+t.Name()), container.WithCmd("echo"))
poll.WaitOn(t, container.IsStopped(ctx, client, id), poll.WithDelay(100*time.Millisecond))