update vendor
Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
This commit is contained in:
parent
19a32db84d
commit
94d1cfbfbf
10501 changed files with 2307943 additions and 29279 deletions
130
vendor/github.com/docker/docker-ce/components/engine/integration/build/build_session_test.go
generated
vendored
Normal file
130
vendor/github.com/docker/docker-ce/components/engine/integration/build/build_session_test.go
generated
vendored
Normal file
|
@ -0,0 +1,130 @@
|
|||
package build
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
dclient "github.com/docker/docker/client"
|
||||
"github.com/docker/docker/internal/test/fakecontext"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/session/filesync"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestBuildWithSession(t *testing.T) {
|
||||
skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild)
|
||||
|
||||
client := testEnv.APIClient()
|
||||
|
||||
dockerfile := `
|
||||
FROM busybox
|
||||
COPY file /
|
||||
RUN cat /file
|
||||
`
|
||||
|
||||
fctx := fakecontext.New(t, "",
|
||||
fakecontext.WithFile("file", "some content"),
|
||||
)
|
||||
defer fctx.Close()
|
||||
|
||||
out := testBuildWithSession(t, client, client.DaemonHost(), fctx.Dir, dockerfile)
|
||||
assert.Check(t, is.Contains(out, "some content"))
|
||||
|
||||
fctx.Add("second", "contentcontent")
|
||||
|
||||
dockerfile += `
|
||||
COPY second /
|
||||
RUN cat /second
|
||||
`
|
||||
|
||||
out = testBuildWithSession(t, client, client.DaemonHost(), fctx.Dir, dockerfile)
|
||||
assert.Check(t, is.Equal(strings.Count(out, "Using cache"), 2))
|
||||
assert.Check(t, is.Contains(out, "contentcontent"))
|
||||
|
||||
du, err := client.DiskUsage(context.TODO())
|
||||
assert.Check(t, err)
|
||||
assert.Check(t, du.BuilderSize > 10)
|
||||
|
||||
out = testBuildWithSession(t, client, client.DaemonHost(), fctx.Dir, dockerfile)
|
||||
assert.Check(t, is.Equal(strings.Count(out, "Using cache"), 4))
|
||||
|
||||
du2, err := client.DiskUsage(context.TODO())
|
||||
assert.Check(t, err)
|
||||
assert.Check(t, is.Equal(du.BuilderSize, du2.BuilderSize))
|
||||
|
||||
// rebuild with regular tar, confirm cache still applies
|
||||
fctx.Add("Dockerfile", dockerfile)
|
||||
// FIXME(vdemeester) use sock here
|
||||
res, body, err := request.Do(
|
||||
"/build",
|
||||
request.Host(client.DaemonHost()),
|
||||
request.Method(http.MethodPost),
|
||||
request.RawContent(fctx.AsTarReader(t)),
|
||||
request.ContentType("application/x-tar"))
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(http.StatusOK, res.StatusCode))
|
||||
|
||||
outBytes, err := request.ReadBody(body)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(string(outBytes), "Successfully built"))
|
||||
assert.Check(t, is.Equal(strings.Count(string(outBytes), "Using cache"), 4))
|
||||
|
||||
_, err = client.BuildCachePrune(context.TODO(), types.BuildCachePruneOptions{All: true})
|
||||
assert.Check(t, err)
|
||||
|
||||
du, err = client.DiskUsage(context.TODO())
|
||||
assert.Check(t, err)
|
||||
assert.Check(t, is.Equal(du.BuilderSize, int64(0)))
|
||||
}
|
||||
|
||||
func testBuildWithSession(t *testing.T, client dclient.APIClient, daemonHost string, dir, dockerfile string) (outStr string) {
|
||||
ctx := context.Background()
|
||||
sess, err := session.NewSession(ctx, "foo1", "foo")
|
||||
assert.Check(t, err)
|
||||
|
||||
fsProvider := filesync.NewFSSyncProvider([]filesync.SyncedDir{
|
||||
{Dir: dir},
|
||||
})
|
||||
sess.Allow(fsProvider)
|
||||
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
g.Go(func() error {
|
||||
return sess.Run(ctx, client.DialSession)
|
||||
})
|
||||
|
||||
g.Go(func() error {
|
||||
// FIXME use sock here
|
||||
res, body, err := request.Do(
|
||||
"/build?remote=client-session&session="+sess.ID(),
|
||||
request.Host(daemonHost),
|
||||
request.Method(http.MethodPost),
|
||||
request.With(func(req *http.Request) error {
|
||||
req.Body = ioutil.NopCloser(strings.NewReader(dockerfile))
|
||||
return nil
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
assert.Check(t, is.DeepEqual(res.StatusCode, http.StatusOK))
|
||||
out, err := request.ReadBody(body)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(string(out), "Successfully built"))
|
||||
sess.Close()
|
||||
outStr = string(out)
|
||||
return nil
|
||||
})
|
||||
|
||||
err = g.Wait()
|
||||
assert.Check(t, err)
|
||||
return
|
||||
}
|
103
vendor/github.com/docker/docker-ce/components/engine/integration/build/build_squash_test.go
generated
vendored
Normal file
103
vendor/github.com/docker/docker-ce/components/engine/integration/build/build_squash_test.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
package build
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/fakecontext"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestBuildSquashParent(t *testing.T) {
|
||||
skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild)
|
||||
|
||||
client := testEnv.APIClient()
|
||||
|
||||
dockerfile := `
|
||||
FROM busybox
|
||||
RUN echo hello > /hello
|
||||
RUN echo world >> /hello
|
||||
RUN echo hello > /remove_me
|
||||
ENV HELLO world
|
||||
RUN rm /remove_me
|
||||
`
|
||||
|
||||
// build and get the ID that we can use later for history comparison
|
||||
ctx := context.Background()
|
||||
source := fakecontext.New(t, "", fakecontext.WithDockerfile(dockerfile))
|
||||
defer source.Close()
|
||||
|
||||
name := "test"
|
||||
resp, err := client.ImageBuild(ctx,
|
||||
source.AsTarReader(t),
|
||||
types.ImageBuildOptions{
|
||||
Remove: true,
|
||||
ForceRemove: true,
|
||||
Tags: []string{name},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
assert.NilError(t, err)
|
||||
|
||||
inspect, _, err := client.ImageInspectWithRaw(ctx, name)
|
||||
assert.NilError(t, err)
|
||||
origID := inspect.ID
|
||||
|
||||
// build with squash
|
||||
resp, err = client.ImageBuild(ctx,
|
||||
source.AsTarReader(t),
|
||||
types.ImageBuildOptions{
|
||||
Remove: true,
|
||||
ForceRemove: true,
|
||||
Squash: true,
|
||||
Tags: []string{name},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
assert.NilError(t, err)
|
||||
|
||||
cid := container.Run(t, ctx, client,
|
||||
container.WithImage(name),
|
||||
container.WithCmd("/bin/sh", "-c", "cat /hello"),
|
||||
)
|
||||
reader, err := client.ContainerLogs(ctx, cid, types.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
actualStdout := new(bytes.Buffer)
|
||||
actualStderr := ioutil.Discard
|
||||
_, err = stdcopy.StdCopy(actualStdout, actualStderr, reader)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(strings.TrimSpace(actualStdout.String()), "hello\nworld"))
|
||||
|
||||
container.Run(t, ctx, client,
|
||||
container.WithImage(name),
|
||||
container.WithCmd("/bin/sh", "-c", "[ ! -f /remove_me ]"),
|
||||
)
|
||||
container.Run(t, ctx, client,
|
||||
container.WithImage(name),
|
||||
container.WithCmd("/bin/sh", "-c", `[ "$(echo $HELLO)" == "world" ]`),
|
||||
)
|
||||
|
||||
origHistory, err := client.ImageHistory(ctx, origID)
|
||||
assert.NilError(t, err)
|
||||
testHistory, err := client.ImageHistory(ctx, name)
|
||||
assert.NilError(t, err)
|
||||
|
||||
inspect, _, err = client.ImageInspectWithRaw(ctx, name)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(testHistory, len(origHistory)+1))
|
||||
assert.Check(t, is.Len(inspect.RootFS.Layers, 2))
|
||||
}
|
460
vendor/github.com/docker/docker-ce/components/engine/integration/build/build_test.go
generated
vendored
Normal file
460
vendor/github.com/docker/docker-ce/components/engine/integration/build/build_test.go
generated
vendored
Normal file
|
@ -0,0 +1,460 @@
|
|||
package build // import "github.com/docker/docker/integration/build"
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/internal/test/fakecontext"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestBuildWithRemoveAndForceRemove(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
t.Parallel()
|
||||
cases := []struct {
|
||||
name string
|
||||
dockerfile string
|
||||
numberOfIntermediateContainers int
|
||||
rm bool
|
||||
forceRm bool
|
||||
}{
|
||||
{
|
||||
name: "successful build with no removal",
|
||||
dockerfile: `FROM busybox
|
||||
RUN exit 0
|
||||
RUN exit 0`,
|
||||
numberOfIntermediateContainers: 2,
|
||||
rm: false,
|
||||
forceRm: false,
|
||||
},
|
||||
{
|
||||
name: "successful build with remove",
|
||||
dockerfile: `FROM busybox
|
||||
RUN exit 0
|
||||
RUN exit 0`,
|
||||
numberOfIntermediateContainers: 0,
|
||||
rm: true,
|
||||
forceRm: false,
|
||||
},
|
||||
{
|
||||
name: "successful build with remove and force remove",
|
||||
dockerfile: `FROM busybox
|
||||
RUN exit 0
|
||||
RUN exit 0`,
|
||||
numberOfIntermediateContainers: 0,
|
||||
rm: true,
|
||||
forceRm: true,
|
||||
},
|
||||
{
|
||||
name: "failed build with no removal",
|
||||
dockerfile: `FROM busybox
|
||||
RUN exit 0
|
||||
RUN exit 1`,
|
||||
numberOfIntermediateContainers: 2,
|
||||
rm: false,
|
||||
forceRm: false,
|
||||
},
|
||||
{
|
||||
name: "failed build with remove",
|
||||
dockerfile: `FROM busybox
|
||||
RUN exit 0
|
||||
RUN exit 1`,
|
||||
numberOfIntermediateContainers: 1,
|
||||
rm: true,
|
||||
forceRm: false,
|
||||
},
|
||||
{
|
||||
name: "failed build with remove and force remove",
|
||||
dockerfile: `FROM busybox
|
||||
RUN exit 0
|
||||
RUN exit 1`,
|
||||
numberOfIntermediateContainers: 0,
|
||||
rm: true,
|
||||
forceRm: true,
|
||||
},
|
||||
}
|
||||
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
dockerfile := []byte(c.dockerfile)
|
||||
|
||||
buff := bytes.NewBuffer(nil)
|
||||
tw := tar.NewWriter(buff)
|
||||
assert.NilError(t, tw.WriteHeader(&tar.Header{
|
||||
Name: "Dockerfile",
|
||||
Size: int64(len(dockerfile)),
|
||||
}))
|
||||
_, err := tw.Write(dockerfile)
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, tw.Close())
|
||||
resp, err := client.ImageBuild(ctx, buff, types.ImageBuildOptions{Remove: c.rm, ForceRemove: c.forceRm, NoCache: true})
|
||||
assert.NilError(t, err)
|
||||
defer resp.Body.Close()
|
||||
filter, err := buildContainerIdsFilter(resp.Body)
|
||||
assert.NilError(t, err)
|
||||
remainingContainers, err := client.ContainerList(ctx, types.ContainerListOptions{Filters: filter, All: true})
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, c.numberOfIntermediateContainers, len(remainingContainers), "Expected %v remaining intermediate containers, got %v", c.numberOfIntermediateContainers, len(remainingContainers))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func buildContainerIdsFilter(buildOutput io.Reader) (filters.Args, error) {
|
||||
const intermediateContainerPrefix = " ---> Running in "
|
||||
filter := filters.NewArgs()
|
||||
|
||||
dec := json.NewDecoder(buildOutput)
|
||||
for {
|
||||
m := jsonmessage.JSONMessage{}
|
||||
err := dec.Decode(&m)
|
||||
if err == io.EOF {
|
||||
return filter, nil
|
||||
}
|
||||
if err != nil {
|
||||
return filter, err
|
||||
}
|
||||
if ix := strings.Index(m.Stream, intermediateContainerPrefix); ix != -1 {
|
||||
filter.Add("id", strings.TrimSpace(m.Stream[ix+len(intermediateContainerPrefix):]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildMultiStageParentConfig(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.35"), "broken in earlier versions")
|
||||
dockerfile := `
|
||||
FROM busybox AS stage0
|
||||
ENV WHO=parent
|
||||
WORKDIR /foo
|
||||
|
||||
FROM stage0
|
||||
ENV WHO=sibling1
|
||||
WORKDIR sub1
|
||||
|
||||
FROM stage0
|
||||
WORKDIR sub2
|
||||
`
|
||||
ctx := context.Background()
|
||||
source := fakecontext.New(t, "", fakecontext.WithDockerfile(dockerfile))
|
||||
defer source.Close()
|
||||
|
||||
apiclient := testEnv.APIClient()
|
||||
resp, err := apiclient.ImageBuild(ctx,
|
||||
source.AsTarReader(t),
|
||||
types.ImageBuildOptions{
|
||||
Remove: true,
|
||||
ForceRemove: true,
|
||||
Tags: []string{"build1"},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
assert.NilError(t, err)
|
||||
|
||||
image, _, err := apiclient.ImageInspectWithRaw(ctx, "build1")
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, is.Equal("/foo/sub2", image.Config.WorkingDir))
|
||||
assert.Check(t, is.Contains(image.Config.Env, "WHO=parent"))
|
||||
}
|
||||
|
||||
// Test cases in #36996
|
||||
func TestBuildLabelWithTargets(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "test added after 1.38")
|
||||
bldName := "build-a"
|
||||
testLabels := map[string]string{
|
||||
"foo": "bar",
|
||||
"dead": "beef",
|
||||
}
|
||||
|
||||
dockerfile := `
|
||||
FROM busybox AS target-a
|
||||
CMD ["/dev"]
|
||||
LABEL label-a=inline-a
|
||||
FROM busybox AS target-b
|
||||
CMD ["/dist"]
|
||||
LABEL label-b=inline-b
|
||||
`
|
||||
|
||||
ctx := context.Background()
|
||||
source := fakecontext.New(t, "", fakecontext.WithDockerfile(dockerfile))
|
||||
defer source.Close()
|
||||
|
||||
apiclient := testEnv.APIClient()
|
||||
// For `target-a` build
|
||||
resp, err := apiclient.ImageBuild(ctx,
|
||||
source.AsTarReader(t),
|
||||
types.ImageBuildOptions{
|
||||
Remove: true,
|
||||
ForceRemove: true,
|
||||
Tags: []string{bldName},
|
||||
Labels: testLabels,
|
||||
Target: "target-a",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
assert.NilError(t, err)
|
||||
|
||||
image, _, err := apiclient.ImageInspectWithRaw(ctx, bldName)
|
||||
assert.NilError(t, err)
|
||||
|
||||
testLabels["label-a"] = "inline-a"
|
||||
for k, v := range testLabels {
|
||||
x, ok := image.Config.Labels[k]
|
||||
assert.Assert(t, ok)
|
||||
assert.Assert(t, x == v)
|
||||
}
|
||||
|
||||
// For `target-b` build
|
||||
bldName = "build-b"
|
||||
delete(testLabels, "label-a")
|
||||
resp, err = apiclient.ImageBuild(ctx,
|
||||
source.AsTarReader(t),
|
||||
types.ImageBuildOptions{
|
||||
Remove: true,
|
||||
ForceRemove: true,
|
||||
Tags: []string{bldName},
|
||||
Labels: testLabels,
|
||||
Target: "target-b",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
assert.NilError(t, err)
|
||||
|
||||
image, _, err = apiclient.ImageInspectWithRaw(ctx, bldName)
|
||||
assert.NilError(t, err)
|
||||
|
||||
testLabels["label-b"] = "inline-b"
|
||||
for k, v := range testLabels {
|
||||
x, ok := image.Config.Labels[k]
|
||||
assert.Assert(t, ok)
|
||||
assert.Assert(t, x == v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildWithEmptyLayers(t *testing.T) {
|
||||
dockerfile := `
|
||||
FROM busybox
|
||||
COPY 1/ /target/
|
||||
COPY 2/ /target/
|
||||
COPY 3/ /target/
|
||||
`
|
||||
ctx := context.Background()
|
||||
source := fakecontext.New(t, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
fakecontext.WithFile("1/a", "asdf"),
|
||||
fakecontext.WithFile("2/a", "asdf"),
|
||||
fakecontext.WithFile("3/a", "asdf"))
|
||||
defer source.Close()
|
||||
|
||||
apiclient := testEnv.APIClient()
|
||||
resp, err := apiclient.ImageBuild(ctx,
|
||||
source.AsTarReader(t),
|
||||
types.ImageBuildOptions{
|
||||
Remove: true,
|
||||
ForceRemove: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
// TestBuildMultiStageOnBuild checks that ONBUILD commands are applied to
|
||||
// multiple subsequent stages
|
||||
// #35652
|
||||
func TestBuildMultiStageOnBuild(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.33"), "broken in earlier versions")
|
||||
defer setupTest(t)()
|
||||
// test both metadata and layer based commands as they may be implemented differently
|
||||
dockerfile := `FROM busybox AS stage1
|
||||
ONBUILD RUN echo 'foo' >somefile
|
||||
ONBUILD ENV bar=baz
|
||||
|
||||
FROM stage1
|
||||
RUN cat somefile # fails if ONBUILD RUN fails
|
||||
|
||||
FROM stage1
|
||||
RUN cat somefile`
|
||||
|
||||
ctx := context.Background()
|
||||
source := fakecontext.New(t, "",
|
||||
fakecontext.WithDockerfile(dockerfile))
|
||||
defer source.Close()
|
||||
|
||||
apiclient := testEnv.APIClient()
|
||||
resp, err := apiclient.ImageBuild(ctx,
|
||||
source.AsTarReader(t),
|
||||
types.ImageBuildOptions{
|
||||
Remove: true,
|
||||
ForceRemove: true,
|
||||
})
|
||||
|
||||
out := bytes.NewBuffer(nil)
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
resp.Body.Close()
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, is.Contains(out.String(), "Successfully built"))
|
||||
|
||||
imageIDs, err := getImageIDsFromBuild(out.Bytes())
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(3, len(imageIDs)))
|
||||
|
||||
image, _, err := apiclient.ImageInspectWithRaw(context.Background(), imageIDs[2])
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(image.Config.Env, "bar=baz"))
|
||||
}
|
||||
|
||||
// #35403 #36122
|
||||
func TestBuildUncleanTarFilenames(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.37"), "broken in earlier versions")
|
||||
ctx := context.TODO()
|
||||
defer setupTest(t)()
|
||||
|
||||
dockerfile := `FROM scratch
|
||||
COPY foo /
|
||||
FROM scratch
|
||||
COPY bar /`
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
w := tar.NewWriter(buf)
|
||||
writeTarRecord(t, w, "Dockerfile", dockerfile)
|
||||
writeTarRecord(t, w, "../foo", "foocontents0")
|
||||
writeTarRecord(t, w, "/bar", "barcontents0")
|
||||
err := w.Close()
|
||||
assert.NilError(t, err)
|
||||
|
||||
apiclient := testEnv.APIClient()
|
||||
resp, err := apiclient.ImageBuild(ctx,
|
||||
buf,
|
||||
types.ImageBuildOptions{
|
||||
Remove: true,
|
||||
ForceRemove: true,
|
||||
})
|
||||
|
||||
out := bytes.NewBuffer(nil)
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
resp.Body.Close()
|
||||
assert.NilError(t, err)
|
||||
|
||||
// repeat with changed data should not cause cache hits
|
||||
|
||||
buf = bytes.NewBuffer(nil)
|
||||
w = tar.NewWriter(buf)
|
||||
writeTarRecord(t, w, "Dockerfile", dockerfile)
|
||||
writeTarRecord(t, w, "../foo", "foocontents1")
|
||||
writeTarRecord(t, w, "/bar", "barcontents1")
|
||||
err = w.Close()
|
||||
assert.NilError(t, err)
|
||||
|
||||
resp, err = apiclient.ImageBuild(ctx,
|
||||
buf,
|
||||
types.ImageBuildOptions{
|
||||
Remove: true,
|
||||
ForceRemove: true,
|
||||
})
|
||||
|
||||
out = bytes.NewBuffer(nil)
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
resp.Body.Close()
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, !strings.Contains(out.String(), "Using cache"))
|
||||
}
|
||||
|
||||
// docker/for-linux#135
|
||||
// #35641
|
||||
func TestBuildMultiStageLayerLeak(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.37"), "broken in earlier versions")
|
||||
ctx := context.TODO()
|
||||
defer setupTest(t)()
|
||||
|
||||
// all commands need to match until COPY
|
||||
dockerfile := `FROM busybox
|
||||
WORKDIR /foo
|
||||
COPY foo .
|
||||
FROM busybox
|
||||
WORKDIR /foo
|
||||
COPY bar .
|
||||
RUN [ -f bar ]
|
||||
RUN [ ! -f foo ]
|
||||
`
|
||||
|
||||
source := fakecontext.New(t, "",
|
||||
fakecontext.WithFile("foo", "0"),
|
||||
fakecontext.WithFile("bar", "1"),
|
||||
fakecontext.WithDockerfile(dockerfile))
|
||||
defer source.Close()
|
||||
|
||||
apiclient := testEnv.APIClient()
|
||||
resp, err := apiclient.ImageBuild(ctx,
|
||||
source.AsTarReader(t),
|
||||
types.ImageBuildOptions{
|
||||
Remove: true,
|
||||
ForceRemove: true,
|
||||
})
|
||||
|
||||
out := bytes.NewBuffer(nil)
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
resp.Body.Close()
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, is.Contains(out.String(), "Successfully built"))
|
||||
}
|
||||
|
||||
func writeTarRecord(t *testing.T, w *tar.Writer, fn, contents string) {
|
||||
err := w.WriteHeader(&tar.Header{
|
||||
Name: fn,
|
||||
Mode: 0600,
|
||||
Size: int64(len(contents)),
|
||||
Typeflag: '0',
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
_, err = w.Write([]byte(contents))
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
type buildLine struct {
|
||||
Stream string
|
||||
Aux struct {
|
||||
ID string
|
||||
}
|
||||
}
|
||||
|
||||
func getImageIDsFromBuild(output []byte) ([]string, error) {
|
||||
var ids []string
|
||||
for _, line := range bytes.Split(output, []byte("\n")) {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
entry := buildLine{}
|
||||
if err := json.Unmarshal(line, &entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if entry.Aux.ID != "" {
|
||||
ids = append(ids, entry.Aux.ID)
|
||||
}
|
||||
}
|
||||
return ids, nil
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/build/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/build/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package build // import "github.com/docker/docker/integration/build"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
433
vendor/github.com/docker/docker-ce/components/engine/integration/config/config_test.go
generated
vendored
Normal file
433
vendor/github.com/docker/docker-ce/components/engine/integration/config/config_test.go
generated
vendored
Normal file
|
@ -0,0 +1,433 @@
|
|||
package config // import "github.com/docker/docker/integration/config"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestConfigList(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// This test case is ported from the original TestConfigsEmptyList
|
||||
configs, err := client.ConfigList(ctx, types.ConfigListOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(len(configs), 0))
|
||||
|
||||
testName0 := "test0-" + t.Name()
|
||||
testName1 := "test1-" + t.Name()
|
||||
testNames := []string{testName0, testName1}
|
||||
sort.Strings(testNames)
|
||||
|
||||
// create config test0
|
||||
createConfig(ctx, t, client, testName0, []byte("TESTINGDATA0"), map[string]string{"type": "test"})
|
||||
|
||||
config1ID := createConfig(ctx, t, client, testName1, []byte("TESTINGDATA1"), map[string]string{"type": "production"})
|
||||
|
||||
// test by `config ls`
|
||||
entries, err := client.ConfigList(ctx, types.ConfigListOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(configNamesFromList(entries), testNames))
|
||||
|
||||
testCases := []struct {
|
||||
filters filters.Args
|
||||
expected []string
|
||||
}{
|
||||
// test filter by name `config ls --filter name=xxx`
|
||||
{
|
||||
filters: filters.NewArgs(filters.Arg("name", testName0)),
|
||||
expected: []string{testName0},
|
||||
},
|
||||
// test filter by id `config ls --filter id=xxx`
|
||||
{
|
||||
filters: filters.NewArgs(filters.Arg("id", config1ID)),
|
||||
expected: []string{testName1},
|
||||
},
|
||||
// test filter by label `config ls --filter label=xxx`
|
||||
{
|
||||
filters: filters.NewArgs(filters.Arg("label", "type")),
|
||||
expected: testNames,
|
||||
},
|
||||
{
|
||||
filters: filters.NewArgs(filters.Arg("label", "type=test")),
|
||||
expected: []string{testName0},
|
||||
},
|
||||
{
|
||||
filters: filters.NewArgs(filters.Arg("label", "type=production")),
|
||||
expected: []string{testName1},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
entries, err = client.ConfigList(ctx, types.ConfigListOptions{
|
||||
Filters: tc.filters,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(configNamesFromList(entries), tc.expected))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func createConfig(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string {
|
||||
config, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: name,
|
||||
Labels: labels,
|
||||
},
|
||||
Data: data,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, config.ID != "")
|
||||
return config.ID
|
||||
}
|
||||
|
||||
func TestConfigsCreateAndDelete(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
testName := "test_config-" + t.Name()
|
||||
|
||||
// This test case is ported from the original TestConfigsCreate
|
||||
configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
|
||||
|
||||
insp, _, err := client.ConfigInspectWithRaw(ctx, configID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.Spec.Name, testName))
|
||||
|
||||
// This test case is ported from the original TestConfigsDelete
|
||||
err = client.ConfigRemove(ctx, configID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
|
||||
assert.Check(t, is.ErrorContains(err, "No such config"))
|
||||
}
|
||||
|
||||
func TestConfigsUpdate(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
testName := "test_config-" + t.Name()
|
||||
|
||||
// This test case is ported from the original TestConfigsCreate
|
||||
configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
|
||||
|
||||
insp, _, err := client.ConfigInspectWithRaw(ctx, configID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.ID, configID))
|
||||
|
||||
// test UpdateConfig with full ID
|
||||
insp.Spec.Labels = map[string]string{"test": "test1"}
|
||||
err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec)
|
||||
assert.NilError(t, err)
|
||||
|
||||
insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test1"))
|
||||
|
||||
// test UpdateConfig with full name
|
||||
insp.Spec.Labels = map[string]string{"test": "test2"}
|
||||
err = client.ConfigUpdate(ctx, testName, insp.Version, insp.Spec)
|
||||
assert.NilError(t, err)
|
||||
|
||||
insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test2"))
|
||||
|
||||
// test UpdateConfig with prefix ID
|
||||
insp.Spec.Labels = map[string]string{"test": "test3"}
|
||||
err = client.ConfigUpdate(ctx, configID[:1], insp.Version, insp.Spec)
|
||||
assert.NilError(t, err)
|
||||
|
||||
insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test3"))
|
||||
|
||||
// test UpdateConfig in updating Data which is not supported in daemon
|
||||
// this test will produce an error in func UpdateConfig
|
||||
insp.Spec.Data = []byte("TESTINGDATA2")
|
||||
err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec)
|
||||
assert.Check(t, is.ErrorContains(err, "only updates to Labels are allowed"))
|
||||
}
|
||||
|
||||
func TestTemplatedConfig(t *testing.T) {
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
|
||||
referencedSecretName := "referencedsecret-" + t.Name()
|
||||
referencedSecretSpec := swarmtypes.SecretSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: referencedSecretName,
|
||||
},
|
||||
Data: []byte("this is a secret"),
|
||||
}
|
||||
referencedSecret, err := client.SecretCreate(ctx, referencedSecretSpec)
|
||||
assert.Check(t, err)
|
||||
|
||||
referencedConfigName := "referencedconfig-" + t.Name()
|
||||
referencedConfigSpec := swarmtypes.ConfigSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: referencedConfigName,
|
||||
},
|
||||
Data: []byte("this is a config"),
|
||||
}
|
||||
referencedConfig, err := client.ConfigCreate(ctx, referencedConfigSpec)
|
||||
assert.Check(t, err)
|
||||
|
||||
templatedConfigName := "templated_config-" + t.Name()
|
||||
configSpec := swarmtypes.ConfigSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: templatedConfigName,
|
||||
},
|
||||
Templating: &swarmtypes.Driver{
|
||||
Name: "golang",
|
||||
},
|
||||
Data: []byte("SERVICE_NAME={{.Service.Name}}\n" +
|
||||
"{{secret \"referencedsecrettarget\"}}\n" +
|
||||
"{{config \"referencedconfigtarget\"}}\n"),
|
||||
}
|
||||
|
||||
templatedConfig, err := client.ConfigCreate(ctx, configSpec)
|
||||
assert.Check(t, err)
|
||||
|
||||
serviceID := swarm.CreateService(t, d,
|
||||
swarm.ServiceWithConfig(
|
||||
&swarmtypes.ConfigReference{
|
||||
File: &swarmtypes.ConfigReferenceFileTarget{
|
||||
Name: "/" + templatedConfigName,
|
||||
UID: "0",
|
||||
GID: "0",
|
||||
Mode: 0600,
|
||||
},
|
||||
ConfigID: templatedConfig.ID,
|
||||
ConfigName: templatedConfigName,
|
||||
},
|
||||
),
|
||||
swarm.ServiceWithConfig(
|
||||
&swarmtypes.ConfigReference{
|
||||
File: &swarmtypes.ConfigReferenceFileTarget{
|
||||
Name: "referencedconfigtarget",
|
||||
UID: "0",
|
||||
GID: "0",
|
||||
Mode: 0600,
|
||||
},
|
||||
ConfigID: referencedConfig.ID,
|
||||
ConfigName: referencedConfigName,
|
||||
},
|
||||
),
|
||||
swarm.ServiceWithSecret(
|
||||
&swarmtypes.SecretReference{
|
||||
File: &swarmtypes.SecretReferenceFileTarget{
|
||||
Name: "referencedsecrettarget",
|
||||
UID: "0",
|
||||
GID: "0",
|
||||
Mode: 0600,
|
||||
},
|
||||
SecretID: referencedSecret.ID,
|
||||
SecretName: referencedSecretName,
|
||||
},
|
||||
),
|
||||
swarm.ServiceWithName("svc"),
|
||||
)
|
||||
|
||||
var tasks []swarmtypes.Task
|
||||
waitAndAssert(t, 60*time.Second, func(t *testing.T) bool {
|
||||
tasks = swarm.GetRunningTasks(t, d, serviceID)
|
||||
return len(tasks) > 0
|
||||
})
|
||||
|
||||
task := tasks[0]
|
||||
waitAndAssert(t, 60*time.Second, func(t *testing.T) bool {
|
||||
if task.NodeID == "" || (task.Status.ContainerStatus == nil || task.Status.ContainerStatus.ContainerID == "") {
|
||||
task, _, _ = client.TaskInspectWithRaw(context.Background(), task.ID)
|
||||
}
|
||||
return task.NodeID != "" && task.Status.ContainerStatus != nil && task.Status.ContainerStatus.ContainerID != ""
|
||||
})
|
||||
|
||||
attach := swarm.ExecTask(t, d, task, types.ExecConfig{
|
||||
Cmd: []string{"/bin/cat", "/" + templatedConfigName},
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
})
|
||||
|
||||
expect := "SERVICE_NAME=svc\n" +
|
||||
"this is a secret\n" +
|
||||
"this is a config\n"
|
||||
assertAttachedStream(t, attach, expect)
|
||||
|
||||
attach = swarm.ExecTask(t, d, task, types.ExecConfig{
|
||||
Cmd: []string{"mount"},
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
})
|
||||
assertAttachedStream(t, attach, "tmpfs on /"+templatedConfigName+" type tmpfs")
|
||||
}
|
||||
|
||||
func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
_, err := stdcopy.StdCopy(buf, buf, attach.Reader)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(buf.String(), expect))
|
||||
}
|
||||
|
||||
func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool) {
|
||||
t.Helper()
|
||||
after := time.After(timeout)
|
||||
for {
|
||||
select {
|
||||
case <-after:
|
||||
t.Fatalf("timed out waiting for condition")
|
||||
default:
|
||||
}
|
||||
if f(t) {
|
||||
return
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigInspect(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
testName := t.Name()
|
||||
configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
|
||||
|
||||
insp, body, err := client.ConfigInspectWithRaw(ctx, configID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.Spec.Name, testName))
|
||||
|
||||
var config swarmtypes.Config
|
||||
err = json.Unmarshal(body, &config)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(config, insp))
|
||||
}
|
||||
|
||||
func TestConfigCreateWithLabels(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
labels := map[string]string{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
}
|
||||
testName := t.Name()
|
||||
configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), labels)
|
||||
|
||||
insp, _, err := client.ConfigInspectWithRaw(ctx, configID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.Spec.Name, testName))
|
||||
assert.Check(t, is.Equal(2, len(insp.Spec.Labels)))
|
||||
assert.Check(t, is.Equal("value1", insp.Spec.Labels["key1"]))
|
||||
assert.Check(t, is.Equal("value2", insp.Spec.Labels["key2"]))
|
||||
}
|
||||
|
||||
// Test case for 28884
|
||||
func TestConfigCreateResolve(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
configName := "test_config_" + t.Name()
|
||||
|
||||
configID := createConfig(ctx, t, client, configName, []byte("foo"), nil)
|
||||
fakeName := configID
|
||||
fakeID := createConfig(ctx, t, client, fakeName, []byte("fake foo"), nil)
|
||||
|
||||
entries, err := client.ConfigList(ctx, types.ConfigListOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, is.Contains(configNamesFromList(entries), configName))
|
||||
assert.Assert(t, is.Contains(configNamesFromList(entries), fakeName))
|
||||
|
||||
err = client.ConfigRemove(ctx, configID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Fake one will remain
|
||||
entries, err = client.ConfigList(ctx, types.ConfigListOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, is.DeepEqual(configNamesFromList(entries), []string{fakeName}))
|
||||
|
||||
// Remove based on name prefix of the fake one
|
||||
// (which is the same as the ID of foo one) should not work
|
||||
// as search is only done based on:
|
||||
// - Full ID
|
||||
// - Full Name
|
||||
// - Partial ID (prefix)
|
||||
err = client.ConfigRemove(ctx, configID[:5])
|
||||
assert.Assert(t, nil != err)
|
||||
entries, err = client.ConfigList(ctx, types.ConfigListOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, is.DeepEqual(configNamesFromList(entries), []string{fakeName}))
|
||||
|
||||
// Remove based on ID prefix of the fake one should succeed
|
||||
err = client.ConfigRemove(ctx, fakeID[:5])
|
||||
assert.NilError(t, err)
|
||||
entries, err = client.ConfigList(ctx, types.ConfigListOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, is.Equal(0, len(entries)))
|
||||
}
|
||||
|
||||
func configNamesFromList(entries []swarmtypes.Config) []string {
|
||||
var values []string
|
||||
for _, entry := range entries {
|
||||
values = append(values, entry.Spec.Name)
|
||||
}
|
||||
sort.Strings(values)
|
||||
return values
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/config/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/config/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package config // import "github.com/docker/docker/integration/config"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
65
vendor/github.com/docker/docker-ce/components/engine/integration/container/copy_test.go
generated
vendored
Normal file
65
vendor/github.com/docker/docker-ce/components/engine/integration/container/copy_test.go
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestCopyFromContainerPathDoesNotExist(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
|
||||
ctx := context.Background()
|
||||
apiclient := testEnv.APIClient()
|
||||
cid := container.Create(t, ctx, apiclient)
|
||||
|
||||
_, _, err := apiclient.CopyFromContainer(ctx, cid, "/dne")
|
||||
assert.Check(t, client.IsErrNotFound(err))
|
||||
expected := fmt.Sprintf("No such container:path: %s:%s", cid, "/dne")
|
||||
assert.Check(t, is.ErrorContains(err, expected))
|
||||
}
|
||||
|
||||
func TestCopyFromContainerPathIsNotDir(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
skip.If(t, testEnv.OSType == "windows")
|
||||
|
||||
ctx := context.Background()
|
||||
apiclient := testEnv.APIClient()
|
||||
cid := container.Create(t, ctx, apiclient)
|
||||
|
||||
_, _, err := apiclient.CopyFromContainer(ctx, cid, "/etc/passwd/")
|
||||
assert.Assert(t, is.ErrorContains(err, "not a directory"))
|
||||
}
|
||||
|
||||
func TestCopyToContainerPathDoesNotExist(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
skip.If(t, testEnv.OSType == "windows")
|
||||
|
||||
ctx := context.Background()
|
||||
apiclient := testEnv.APIClient()
|
||||
cid := container.Create(t, ctx, apiclient)
|
||||
|
||||
err := apiclient.CopyToContainer(ctx, cid, "/dne", nil, types.CopyToContainerOptions{})
|
||||
assert.Check(t, client.IsErrNotFound(err))
|
||||
expected := fmt.Sprintf("No such container:path: %s:%s", cid, "/dne")
|
||||
assert.Check(t, is.ErrorContains(err, expected))
|
||||
}
|
||||
|
||||
func TestCopyToContainerPathIsNotDir(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
skip.If(t, testEnv.OSType == "windows")
|
||||
|
||||
ctx := context.Background()
|
||||
apiclient := testEnv.APIClient()
|
||||
cid := container.Create(t, ctx, apiclient)
|
||||
|
||||
err := apiclient.CopyToContainer(ctx, cid, "/etc/passwd/", nil, types.CopyToContainerOptions{})
|
||||
assert.Assert(t, is.ErrorContains(err, "not a directory"))
|
||||
}
|
303
vendor/github.com/docker/docker-ce/components/engine/integration/container/create_test.go
generated
vendored
Normal file
303
vendor/github.com/docker/docker-ce/components/engine/integration/container/create_test.go
generated
vendored
Normal file
|
@ -0,0 +1,303 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
ctr "github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/oci"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestCreateFailsWhenIdentifierDoesNotExist(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
testCases := []struct {
|
||||
doc string
|
||||
image string
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
doc: "image and tag",
|
||||
image: "test456:v1",
|
||||
expectedError: "No such image: test456:v1",
|
||||
},
|
||||
{
|
||||
doc: "image no tag",
|
||||
image: "test456",
|
||||
expectedError: "No such image: test456",
|
||||
},
|
||||
{
|
||||
doc: "digest",
|
||||
image: "sha256:0cb40641836c461bc97c793971d84d758371ed682042457523e4ae701efeaaaa",
|
||||
expectedError: "No such image: sha256:0cb40641836c461bc97c793971d84d758371ed682042457523e4ae701efeaaaa",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := client.ContainerCreate(context.Background(),
|
||||
&container.Config{Image: tc.image},
|
||||
&container.HostConfig{},
|
||||
&network.NetworkingConfig{},
|
||||
"",
|
||||
)
|
||||
assert.Check(t, is.ErrorContains(err, tc.expectedError))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateWithInvalidEnv(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
testCases := []struct {
|
||||
env string
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
env: "",
|
||||
expectedError: "invalid environment variable:",
|
||||
},
|
||||
{
|
||||
env: "=",
|
||||
expectedError: "invalid environment variable: =",
|
||||
},
|
||||
{
|
||||
env: "=foo",
|
||||
expectedError: "invalid environment variable: =foo",
|
||||
},
|
||||
}
|
||||
|
||||
for index, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(strconv.Itoa(index), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := client.ContainerCreate(context.Background(),
|
||||
&container.Config{
|
||||
Image: "busybox",
|
||||
Env: []string{tc.env},
|
||||
},
|
||||
&container.HostConfig{},
|
||||
&network.NetworkingConfig{},
|
||||
"",
|
||||
)
|
||||
assert.Check(t, is.ErrorContains(err, tc.expectedError))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test case for #30166 (target was not validated)
|
||||
func TestCreateTmpfsMountsTarget(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
testCases := []struct {
|
||||
target string
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
target: ".",
|
||||
expectedError: "mount path must be absolute",
|
||||
},
|
||||
{
|
||||
target: "foo",
|
||||
expectedError: "mount path must be absolute",
|
||||
},
|
||||
{
|
||||
target: "/",
|
||||
expectedError: "destination can't be '/'",
|
||||
},
|
||||
{
|
||||
target: "//",
|
||||
expectedError: "destination can't be '/'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
_, err := client.ContainerCreate(context.Background(),
|
||||
&container.Config{
|
||||
Image: "busybox",
|
||||
},
|
||||
&container.HostConfig{
|
||||
Tmpfs: map[string]string{tc.target: ""},
|
||||
},
|
||||
&network.NetworkingConfig{},
|
||||
"",
|
||||
)
|
||||
assert.Check(t, is.ErrorContains(err, tc.expectedError))
|
||||
}
|
||||
}
|
||||
func TestCreateWithCustomMaskedPaths(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
testCases := []struct {
|
||||
maskedPaths []string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
maskedPaths: []string{},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
maskedPaths: nil,
|
||||
expected: oci.DefaultSpec().Linux.MaskedPaths,
|
||||
},
|
||||
{
|
||||
maskedPaths: []string{"/proc/kcore", "/proc/keys"},
|
||||
expected: []string{"/proc/kcore", "/proc/keys"},
|
||||
},
|
||||
}
|
||||
|
||||
checkInspect := func(t *testing.T, ctx context.Context, name string, expected []string) {
|
||||
_, b, err := client.ContainerInspectWithRaw(ctx, name, false)
|
||||
assert.NilError(t, err)
|
||||
|
||||
var inspectJSON map[string]interface{}
|
||||
err = json.Unmarshal(b, &inspectJSON)
|
||||
assert.NilError(t, err)
|
||||
|
||||
cfg, ok := inspectJSON["HostConfig"].(map[string]interface{})
|
||||
assert.Check(t, is.Equal(true, ok), name)
|
||||
|
||||
maskedPaths, ok := cfg["MaskedPaths"].([]interface{})
|
||||
assert.Check(t, is.Equal(true, ok), name)
|
||||
|
||||
mps := []string{}
|
||||
for _, mp := range maskedPaths {
|
||||
mps = append(mps, mp.(string))
|
||||
}
|
||||
|
||||
assert.DeepEqual(t, expected, mps)
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
name := fmt.Sprintf("create-masked-paths-%d", i)
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"true"},
|
||||
}
|
||||
hc := container.HostConfig{}
|
||||
if tc.maskedPaths != nil {
|
||||
hc.MaskedPaths = tc.maskedPaths
|
||||
}
|
||||
|
||||
// Create the container.
|
||||
c, err := client.ContainerCreate(context.Background(),
|
||||
&config,
|
||||
&hc,
|
||||
&network.NetworkingConfig{},
|
||||
name,
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
checkInspect(t, ctx, name, tc.expected)
|
||||
|
||||
// Start the container.
|
||||
err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, ctr.IsInState(ctx, client, c.ID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
checkInspect(t, ctx, name, tc.expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateWithCustomReadonlyPaths(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
testCases := []struct {
|
||||
doc string
|
||||
readonlyPaths []string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
readonlyPaths: []string{},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
readonlyPaths: nil,
|
||||
expected: oci.DefaultSpec().Linux.ReadonlyPaths,
|
||||
},
|
||||
{
|
||||
readonlyPaths: []string{"/proc/asound", "/proc/bus"},
|
||||
expected: []string{"/proc/asound", "/proc/bus"},
|
||||
},
|
||||
}
|
||||
|
||||
checkInspect := func(t *testing.T, ctx context.Context, name string, expected []string) {
|
||||
_, b, err := client.ContainerInspectWithRaw(ctx, name, false)
|
||||
assert.NilError(t, err)
|
||||
|
||||
var inspectJSON map[string]interface{}
|
||||
err = json.Unmarshal(b, &inspectJSON)
|
||||
assert.NilError(t, err)
|
||||
|
||||
cfg, ok := inspectJSON["HostConfig"].(map[string]interface{})
|
||||
assert.Check(t, is.Equal(true, ok), name)
|
||||
|
||||
readonlyPaths, ok := cfg["ReadonlyPaths"].([]interface{})
|
||||
assert.Check(t, is.Equal(true, ok), name)
|
||||
|
||||
rops := []string{}
|
||||
for _, rop := range readonlyPaths {
|
||||
rops = append(rops, rop.(string))
|
||||
}
|
||||
assert.DeepEqual(t, expected, rops)
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
name := fmt.Sprintf("create-readonly-paths-%d", i)
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"true"},
|
||||
}
|
||||
hc := container.HostConfig{}
|
||||
if tc.readonlyPaths != nil {
|
||||
hc.ReadonlyPaths = tc.readonlyPaths
|
||||
}
|
||||
|
||||
// Create the container.
|
||||
c, err := client.ContainerCreate(context.Background(),
|
||||
&config,
|
||||
&hc,
|
||||
&network.NetworkingConfig{},
|
||||
name,
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
checkInspect(t, ctx, name, tc.expected)
|
||||
|
||||
// Start the container.
|
||||
err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, ctr.IsInState(ctx, client, c.ID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
checkInspect(t, ctx, name, tc.expected)
|
||||
}
|
||||
}
|
78
vendor/github.com/docker/docker-ce/components/engine/integration/container/daemon_linux_test.go
generated
vendored
Normal file
78
vendor/github.com/docker/docker-ce/components/engine/integration/container/daemon_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"golang.org/x/sys/unix"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
// This is a regression test for #36145
|
||||
// It ensures that a container can be started when the daemon was improperly
|
||||
// shutdown when the daemon is brought back up.
|
||||
//
|
||||
// The regression is due to improper error handling preventing a container from
|
||||
// being restored and as such have the resources cleaned up.
|
||||
//
|
||||
// To test this, we need to kill dockerd, then kill both the containerd-shim and
|
||||
// the container process, then start dockerd back up and attempt to start the
|
||||
// container again.
|
||||
func TestContainerStartOnDaemonRestart(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run")
|
||||
t.Parallel()
|
||||
|
||||
d := daemon.New(t)
|
||||
d.StartWithBusybox(t, "--iptables=false")
|
||||
defer d.Stop(t)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.Check(t, err, "error creating client")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Create(t, ctx, client)
|
||||
defer client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
err = client.ContainerStart(ctx, cID, types.ContainerStartOptions{})
|
||||
assert.Check(t, err, "error starting test container")
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.Check(t, err, "error getting inspect data")
|
||||
|
||||
ppid := getContainerdShimPid(t, inspect)
|
||||
|
||||
err = d.Kill()
|
||||
assert.Check(t, err, "failed to kill test daemon")
|
||||
|
||||
err = unix.Kill(inspect.State.Pid, unix.SIGKILL)
|
||||
assert.Check(t, err, "failed to kill container process")
|
||||
|
||||
err = unix.Kill(ppid, unix.SIGKILL)
|
||||
assert.Check(t, err, "failed to kill containerd-shim")
|
||||
|
||||
d.Start(t, "--iptables=false")
|
||||
|
||||
err = client.ContainerStart(ctx, cID, types.ContainerStartOptions{})
|
||||
assert.Check(t, err, "failed to start test container")
|
||||
}
|
||||
|
||||
func getContainerdShimPid(t *testing.T, c types.ContainerJSON) int {
|
||||
statB, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/stat", c.State.Pid))
|
||||
assert.Check(t, err, "error looking up containerd-shim pid")
|
||||
|
||||
// ppid is the 4th entry in `/proc/pid/stat`
|
||||
ppid, err := strconv.Atoi(strings.Fields(string(statB))[3])
|
||||
assert.Check(t, err, "error converting ppid field to int")
|
||||
|
||||
assert.Check(t, ppid != 1, "got unexpected ppid")
|
||||
return ppid
|
||||
}
|
42
vendor/github.com/docker/docker-ce/components/engine/integration/container/diff_test.go
generated
vendored
Normal file
42
vendor/github.com/docker/docker-ce/components/engine/integration/container/diff_test.go
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/poll"
|
||||
)
|
||||
|
||||
func TestDiff(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", `mkdir /foo; echo xyzzy > /foo/bar`))
|
||||
|
||||
// Wait for it to exit as cannot diff a running container on Windows, and
|
||||
// it will take a few seconds to exit. Also there's no way in Windows to
|
||||
// differentiate between an Add or a Modify, and all files are under
|
||||
// a "Files/" prefix.
|
||||
expected := []containertypes.ContainerChangeResponseItem{
|
||||
{Kind: archive.ChangeAdd, Path: "/foo"},
|
||||
{Kind: archive.ChangeAdd, Path: "/foo/bar"},
|
||||
}
|
||||
if testEnv.OSType == "windows" {
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond), poll.WithTimeout(60*time.Second))
|
||||
expected = []containertypes.ContainerChangeResponseItem{
|
||||
{Kind: archive.ChangeModify, Path: "Files/foo"},
|
||||
{Kind: archive.ChangeModify, Path: "Files/foo/bar"},
|
||||
}
|
||||
}
|
||||
|
||||
items, err := client.ContainerDiff(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, expected, items)
|
||||
}
|
50
vendor/github.com/docker/docker-ce/components/engine/integration/container/exec_test.go
generated
vendored
Normal file
50
vendor/github.com/docker/docker-ce/components/engine/integration/container/exec_test.go
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestExec(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.35"), "broken in earlier versions")
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithTty(true), container.WithWorkingDir("/root"))
|
||||
|
||||
id, err := client.ContainerExecCreate(ctx, cID,
|
||||
types.ExecConfig{
|
||||
WorkingDir: "/tmp",
|
||||
Env: strslice.StrSlice([]string{"FOO=BAR"}),
|
||||
AttachStdout: true,
|
||||
Cmd: strslice.StrSlice([]string{"sh", "-c", "env"}),
|
||||
},
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
resp, err := client.ContainerExecAttach(ctx, id.ID,
|
||||
types.ExecStartCheck{
|
||||
Detach: false,
|
||||
Tty: false,
|
||||
},
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
defer resp.Close()
|
||||
r, err := ioutil.ReadAll(resp.Reader)
|
||||
assert.NilError(t, err)
|
||||
out := string(r)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, is.Contains(out, "PWD=/tmp"), "exec command not running in expected /tmp working directory")
|
||||
assert.Assert(t, is.Contains(out, "FOO=BAR"), "exec command not running with expected environment variable FOO")
|
||||
}
|
78
vendor/github.com/docker/docker-ce/components/engine/integration/container/export_test.go
generated
vendored
Normal file
78
vendor/github.com/docker/docker-ce/components/engine/integration/container/export_test.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
// export an image and try to import it into a new one
|
||||
func TestExportContainerAndImportImage(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("true"))
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
reference := "repo/testexp:v1"
|
||||
exportResp, err := client.ContainerExport(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
importResp, err := client.ImageImport(ctx, types.ImageImportSource{
|
||||
Source: exportResp,
|
||||
SourceName: "-",
|
||||
}, reference, types.ImageImportOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// If the import is successfully, then the message output should contain
|
||||
// the image ID and match with the output from `docker images`.
|
||||
|
||||
dec := json.NewDecoder(importResp)
|
||||
var jm jsonmessage.JSONMessage
|
||||
err = dec.Decode(&jm)
|
||||
assert.NilError(t, err)
|
||||
|
||||
images, err := client.ImageList(ctx, types.ImageListOptions{
|
||||
Filters: filters.NewArgs(filters.Arg("reference", reference)),
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(jm.Status, images[0].ID))
|
||||
}
|
||||
|
||||
// TestExportContainerAfterDaemonRestart checks that a container
|
||||
// created before start of the currently running dockerd
|
||||
// can be exported (as reported in #36561). To satisfy this
|
||||
// condition, daemon restart is needed after container creation.
|
||||
func TestExportContainerAfterDaemonRestart(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
d := daemon.New(t)
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
d.StartWithBusybox(t)
|
||||
defer d.Stop(t)
|
||||
|
||||
ctx := context.Background()
|
||||
ctrID := container.Create(t, ctx, client)
|
||||
|
||||
d.Restart(t)
|
||||
|
||||
_, err = client.ContainerExport(ctx, ctrID)
|
||||
assert.NilError(t, err)
|
||||
}
|
47
vendor/github.com/docker/docker-ce/components/engine/integration/container/health_test.go
generated
vendored
Normal file
47
vendor/github.com/docker/docker-ce/components/engine/integration/container/health_test.go
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/poll"
|
||||
)
|
||||
|
||||
// TestHealthCheckWorkdir verifies that health-checks inherit the containers'
|
||||
// working-dir.
|
||||
func TestHealthCheckWorkdir(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithTty(true), container.WithWorkingDir("/foo"), func(c *container.TestContainerConfig) {
|
||||
c.Config.Healthcheck = &containertypes.HealthConfig{
|
||||
Test: []string{"CMD-SHELL", "if [ \"$PWD\" = \"/foo\" ]; then exit 0; else exit 1; fi;"},
|
||||
Interval: 50 * time.Millisecond,
|
||||
Retries: 3,
|
||||
}
|
||||
})
|
||||
|
||||
poll.WaitOn(t, pollForHealthStatus(ctx, client, cID, types.Healthy), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
||||
func pollForHealthStatus(ctx context.Context, client client.APIClient, containerID string, healthStatus string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
inspect, err := client.ContainerInspect(ctx, containerID)
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
return poll.Error(err)
|
||||
case inspect.State.Health.Status == healthStatus:
|
||||
return poll.Success()
|
||||
default:
|
||||
return poll.Continue("waiting for container to become %s", healthStatus)
|
||||
}
|
||||
}
|
||||
}
|
48
vendor/github.com/docker/docker-ce/components/engine/integration/container/inspect_test.go
generated
vendored
Normal file
48
vendor/github.com/docker/docker-ce/components/engine/integration/container/inspect_test.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestInspectCpusetInConfigPre120(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || !testEnv.DaemonInfo.CPUSet)
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t, client.WithVersion("1.19"))
|
||||
ctx := context.Background()
|
||||
|
||||
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"),
|
||||
func(c *container.TestContainerConfig) {
|
||||
c.HostConfig.Resources.CpusetCpus = "0"
|
||||
},
|
||||
)
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, name, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
_, body, err := client.ContainerInspectWithRaw(ctx, name, false)
|
||||
assert.NilError(t, err)
|
||||
|
||||
var inspectJSON map[string]interface{}
|
||||
err = json.Unmarshal(body, &inspectJSON)
|
||||
assert.NilError(t, err, "unable to unmarshal body for version 1.19: %s", err)
|
||||
|
||||
config, ok := inspectJSON["Config"]
|
||||
assert.Check(t, is.Equal(true, ok), "Unable to find 'Config'")
|
||||
|
||||
cfg := config.(map[string]interface{})
|
||||
_, ok = cfg["Cpuset"]
|
||||
assert.Check(t, is.Equal(true, ok), "API version 1.19 expected to include Cpuset in 'Config'")
|
||||
}
|
181
vendor/github.com/docker/docker-ce/components/engine/integration/container/ipcmode_test.go
generated
vendored
Normal file
181
vendor/github.com/docker/docker-ce/components/engine/integration/container/ipcmode_test.go
generated
vendored
Normal file
|
@ -0,0 +1,181 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
// testIpcCheckDevExists checks whether a given mount (identified by its
|
||||
// major:minor pair from /proc/self/mountinfo) exists on the host system.
|
||||
//
|
||||
// The format of /proc/self/mountinfo is like:
|
||||
//
|
||||
// 29 23 0:24 / /dev/shm rw,nosuid,nodev shared:4 - tmpfs tmpfs rw
|
||||
// ^^^^\
|
||||
// - this is the minor:major we look for
|
||||
func testIpcCheckDevExists(mm string) (bool, error) {
|
||||
f, err := os.Open("/proc/self/mountinfo")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
s := bufio.NewScanner(f)
|
||||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
if len(fields) < 7 {
|
||||
continue
|
||||
}
|
||||
if fields[2] == mm {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, s.Err()
|
||||
}
|
||||
|
||||
// testIpcNonePrivateShareable is a helper function to test "none",
|
||||
// "private" and "shareable" modes.
|
||||
func testIpcNonePrivateShareable(t *testing.T, mode string, mustBeMounted bool, mustBeShared bool) {
|
||||
defer setupTest(t)()
|
||||
|
||||
cfg := containertypes.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"top"},
|
||||
}
|
||||
hostCfg := containertypes.HostConfig{
|
||||
IpcMode: containertypes.IpcMode(mode),
|
||||
}
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
||||
|
||||
err = client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// get major:minor pair for /dev/shm from container's /proc/self/mountinfo
|
||||
cmd := "awk '($5 == \"/dev/shm\") {printf $3}' /proc/self/mountinfo"
|
||||
result, err := container.Exec(ctx, client, resp.ID, []string{"sh", "-c", cmd})
|
||||
assert.NilError(t, err)
|
||||
mm := result.Combined()
|
||||
if !mustBeMounted {
|
||||
assert.Check(t, is.Equal(mm, ""))
|
||||
// no more checks to perform
|
||||
return
|
||||
}
|
||||
assert.Check(t, is.Equal(true, regexp.MustCompile("^[0-9]+:[0-9]+$").MatchString(mm)))
|
||||
|
||||
shared, err := testIpcCheckDevExists(mm)
|
||||
assert.NilError(t, err)
|
||||
t.Logf("[testIpcPrivateShareable] ipcmode: %v, ipcdev: %v, shared: %v, mustBeShared: %v\n", mode, mm, shared, mustBeShared)
|
||||
assert.Check(t, is.Equal(shared, mustBeShared))
|
||||
}
|
||||
|
||||
// TestIpcModeNone checks the container "none" IPC mode
|
||||
// (--ipc none) works as expected. It makes sure there is no
|
||||
// /dev/shm mount inside the container.
|
||||
func TestIpcModeNone(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || testEnv.IsRemoteDaemon())
|
||||
|
||||
testIpcNonePrivateShareable(t, "none", false, false)
|
||||
}
|
||||
|
||||
// TestAPIIpcModePrivate checks the container private IPC mode
|
||||
// (--ipc private) works as expected. It gets the minor:major pair
|
||||
// of /dev/shm mount from the container, and makes sure there is no
|
||||
// such pair on the host.
|
||||
func TestIpcModePrivate(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || testEnv.IsRemoteDaemon())
|
||||
|
||||
testIpcNonePrivateShareable(t, "private", true, false)
|
||||
}
|
||||
|
||||
// TestAPIIpcModeShareable checks the container shareable IPC mode
|
||||
// (--ipc shareable) works as expected. It gets the minor:major pair
|
||||
// of /dev/shm mount from the container, and makes sure such pair
|
||||
// also exists on the host.
|
||||
func TestIpcModeShareable(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || testEnv.IsRemoteDaemon())
|
||||
|
||||
testIpcNonePrivateShareable(t, "shareable", true, true)
|
||||
}
|
||||
|
||||
// testIpcContainer is a helper function to test --ipc container:NNN mode in various scenarios
|
||||
func testIpcContainer(t *testing.T, donorMode string, mustWork bool) {
|
||||
t.Helper()
|
||||
|
||||
defer setupTest(t)()
|
||||
|
||||
cfg := containertypes.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"top"},
|
||||
}
|
||||
hostCfg := containertypes.HostConfig{
|
||||
IpcMode: containertypes.IpcMode(donorMode),
|
||||
}
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
// create and start the "donor" container
|
||||
resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
||||
name1 := resp.ID
|
||||
|
||||
err = client.ContainerStart(ctx, name1, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// create and start the second container
|
||||
hostCfg.IpcMode = containertypes.IpcMode("container:" + name1)
|
||||
resp, err = client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(len(resp.Warnings), 0))
|
||||
name2 := resp.ID
|
||||
|
||||
err = client.ContainerStart(ctx, name2, types.ContainerStartOptions{})
|
||||
if !mustWork {
|
||||
// start should fail with a specific error
|
||||
assert.Check(t, is.ErrorContains(err, "non-shareable IPC"))
|
||||
// no more checks to perform here
|
||||
return
|
||||
}
|
||||
|
||||
// start should succeed
|
||||
assert.NilError(t, err)
|
||||
|
||||
// check that IPC is shared
|
||||
// 1. create a file in the first container
|
||||
_, err = container.Exec(ctx, client, name1, []string{"sh", "-c", "printf covfefe > /dev/shm/bar"})
|
||||
assert.NilError(t, err)
|
||||
// 2. check it's the same file in the second one
|
||||
result, err := container.Exec(ctx, client, name2, []string{"cat", "/dev/shm/bar"})
|
||||
assert.NilError(t, err)
|
||||
out := result.Combined()
|
||||
assert.Check(t, is.Equal(true, regexp.MustCompile("^covfefe$").MatchString(out)))
|
||||
}
|
||||
|
||||
// TestAPIIpcModeShareableAndPrivate checks that
|
||||
// 1) a container created with --ipc container:ID can use IPC of another shareable container.
|
||||
// 2) a container created with --ipc container:ID can NOT use IPC of another private container.
|
||||
func TestAPIIpcModeShareableAndContainer(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
testIpcContainer(t, "shareable", true)
|
||||
|
||||
testIpcContainer(t, "private", false)
|
||||
}
|
183
vendor/github.com/docker/docker-ce/components/engine/integration/container/kill_test.go
generated
vendored
Normal file
183
vendor/github.com/docker/docker-ce/components/engine/integration/container/kill_test.go
generated
vendored
Normal file
|
@ -0,0 +1,183 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestKillContainerInvalidSignal(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
id := container.Run(t, ctx, client)
|
||||
|
||||
err := client.ContainerKill(ctx, id, "0")
|
||||
assert.Error(t, err, "Error response from daemon: Invalid signal: 0")
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err = client.ContainerKill(ctx, id, "SIG42")
|
||||
assert.Error(t, err, "Error response from daemon: Invalid signal: SIG42")
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
||||
func TestKillContainer(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
testCases := []struct {
|
||||
doc string
|
||||
signal string
|
||||
status string
|
||||
}{
|
||||
{
|
||||
doc: "no signal",
|
||||
signal: "",
|
||||
status: "exited",
|
||||
},
|
||||
{
|
||||
doc: "non killing signal",
|
||||
signal: "SIGWINCH",
|
||||
status: "running",
|
||||
},
|
||||
{
|
||||
doc: "killing signal",
|
||||
signal: "SIGTERM",
|
||||
status: "exited",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
id := container.Run(t, ctx, client)
|
||||
err := client.ContainerKill(ctx, id, tc.signal)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, tc.status), poll.WithDelay(100*time.Millisecond))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKillWithStopSignalAndRestartPolicies(t *testing.T) {
|
||||
skip.If(t, testEnv.OSType != "linux", "Windows only supports 1.25 or later")
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
testCases := []struct {
|
||||
doc string
|
||||
stopsignal string
|
||||
status string
|
||||
}{
|
||||
{
|
||||
doc: "same-signal-disables-restart-policy",
|
||||
stopsignal: "TERM",
|
||||
status: "exited",
|
||||
},
|
||||
{
|
||||
doc: "different-signal-keep-restart-policy",
|
||||
stopsignal: "CONT",
|
||||
status: "running",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
id := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
|
||||
c.Config.StopSignal = tc.stopsignal
|
||||
c.HostConfig.RestartPolicy = containertypes.RestartPolicy{
|
||||
Name: "always",
|
||||
}
|
||||
})
|
||||
err := client.ContainerKill(ctx, id, "TERM")
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, tc.status), poll.WithDelay(100*time.Millisecond))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKillStoppedContainer(t *testing.T) {
|
||||
skip.If(t, testEnv.OSType != "linux") // Windows only supports 1.25 or later
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
id := container.Create(t, ctx, client)
|
||||
err := client.ContainerKill(ctx, id, "SIGKILL")
|
||||
assert.Assert(t, is.ErrorContains(err, ""))
|
||||
assert.Assert(t, is.Contains(err.Error(), "is not running"))
|
||||
}
|
||||
|
||||
func TestKillStoppedContainerAPIPre120(t *testing.T) {
|
||||
skip.If(t, testEnv.OSType != "linux") // Windows only supports 1.25 or later
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t, client.WithVersion("1.19"))
|
||||
id := container.Create(t, ctx, client)
|
||||
err := client.ContainerKill(ctx, id, "SIGKILL")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestKillDifferentUserContainer(t *testing.T) {
|
||||
// TODO Windows: Windows does not yet support -u (Feb 2016).
|
||||
skip.If(t, testEnv.OSType != "linux", "User containers (container.Config.User) are not yet supported on %q platform", testEnv.OSType)
|
||||
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t, client.WithVersion("1.19"))
|
||||
|
||||
id := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
|
||||
c.Config.User = "daemon"
|
||||
})
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerKill(ctx, id, "SIGKILL")
|
||||
assert.NilError(t, err)
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, id, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
||||
func TestInspectOomKilledTrue(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || !testEnv.DaemonInfo.MemoryLimit || !testEnv.DaemonInfo.SwapLimit)
|
||||
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", "x=a; while true; do x=$x$x$x$x; done"), func(c *container.TestContainerConfig) {
|
||||
c.HostConfig.Resources.Memory = 32 * 1024 * 1024
|
||||
})
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(true, inspect.State.OOMKilled))
|
||||
}
|
||||
|
||||
func TestInspectOomKilledFalse(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || !testEnv.DaemonInfo.MemoryLimit || !testEnv.DaemonInfo.SwapLimit)
|
||||
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", "echo hello world"))
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(false, inspect.State.OOMKilled))
|
||||
}
|
57
vendor/github.com/docker/docker-ce/components/engine/integration/container/links_linux_test.go
generated
vendored
Normal file
57
vendor/github.com/docker/docker-ce/components/engine/integration/container/links_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestLinksEtcHostsContentMatch(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
hosts, err := ioutil.ReadFile("/etc/hosts")
|
||||
skip.If(t, os.IsNotExist(err))
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithNetworkMode("host"))
|
||||
res, err := container.Exec(ctx, client, cID, []string{"cat", "/etc/hosts"})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, is.Len(res.Stderr(), 0))
|
||||
assert.Equal(t, 0, res.ExitCode)
|
||||
|
||||
assert.Check(t, is.Equal(string(hosts), res.Stdout()))
|
||||
}
|
||||
|
||||
func TestLinksContainerNames(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
containerA := "first_" + t.Name()
|
||||
containerB := "second_" + t.Name()
|
||||
container.Run(t, ctx, client, container.WithName(containerA))
|
||||
container.Run(t, ctx, client, container.WithName(containerB), container.WithLinks(containerA+":"+containerA))
|
||||
|
||||
f := filters.NewArgs(filters.Arg("name", containerA))
|
||||
|
||||
containers, err := client.ContainerList(ctx, types.ContainerListOptions{
|
||||
Filters: f,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(1, len(containers)))
|
||||
assert.Check(t, is.DeepEqual([]string{"/" + containerA, "/" + containerB + "/" + containerA}, containers[0].Names))
|
||||
}
|
35
vendor/github.com/docker/docker-ce/components/engine/integration/container/logs_test.go
generated
vendored
Normal file
35
vendor/github.com/docker/docker-ce/components/engine/integration/container/logs_test.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
// Regression test for #35370
|
||||
// Makes sure that when following we don't get an EOF error when there are no logs
|
||||
func TestLogsFollowTailEmpty(t *testing.T) {
|
||||
// FIXME(vdemeester) fails on a e2e run on linux...
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
id := container.Run(t, ctx, client, container.WithCmd("sleep", "100000"))
|
||||
|
||||
logs, err := client.ContainerLogs(ctx, id, types.ContainerLogsOptions{ShowStdout: true, Tail: "2"})
|
||||
if logs != nil {
|
||||
defer logs.Close()
|
||||
}
|
||||
assert.Check(t, err)
|
||||
|
||||
_, err = stdcopy.StdCopy(ioutil.Discard, ioutil.Discard, logs)
|
||||
assert.Check(t, err)
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/container/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/container/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
208
vendor/github.com/docker/docker-ce/components/engine/integration/container/mounts_linux_test.go
generated
vendored
Normal file
208
vendor/github.com/docker/docker-ce/components/engine/integration/container/mounts_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,208 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/fs"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestContainerNetworkMountsNoChown(t *testing.T) {
|
||||
// chown only applies to Linux bind mounted volumes; must be same host to verify
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
tmpDir := fs.NewDir(t, "network-file-mounts", fs.WithMode(0755), fs.WithFile("nwfile", "network file bind mount", fs.WithMode(0644)))
|
||||
defer tmpDir.Remove()
|
||||
|
||||
tmpNWFileMount := tmpDir.Join("nwfile")
|
||||
|
||||
config := container.Config{
|
||||
Image: "busybox",
|
||||
}
|
||||
hostConfig := container.HostConfig{
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: "bind",
|
||||
Source: tmpNWFileMount,
|
||||
Target: "/etc/resolv.conf",
|
||||
},
|
||||
{
|
||||
Type: "bind",
|
||||
Source: tmpNWFileMount,
|
||||
Target: "/etc/hostname",
|
||||
},
|
||||
{
|
||||
Type: "bind",
|
||||
Source: tmpNWFileMount,
|
||||
Target: "/etc/hosts",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cli, err := client.NewEnvClient()
|
||||
assert.NilError(t, err)
|
||||
defer cli.Close()
|
||||
|
||||
ctrCreate, err := cli.ContainerCreate(ctx, &config, &hostConfig, &network.NetworkingConfig{}, "")
|
||||
assert.NilError(t, err)
|
||||
// container will exit immediately because of no tty, but we only need the start sequence to test the condition
|
||||
err = cli.ContainerStart(ctx, ctrCreate.ID, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Check that host-located bind mount network file did not change ownership when the container was started
|
||||
// Note: If the user specifies a mountpath from the host, we should not be
|
||||
// attempting to chown files outside the daemon's metadata directory
|
||||
// (represented by `daemon.repository` at init time).
|
||||
// This forces users who want to use user namespaces to handle the
|
||||
// ownership needs of any external files mounted as network files
|
||||
// (/etc/resolv.conf, /etc/hosts, /etc/hostname) separately from the
|
||||
// daemon. In all other volume/bind mount situations we have taken this
|
||||
// same line--we don't chown host file content.
|
||||
// See GitHub PR 34224 for details.
|
||||
statT, err := system.Stat(tmpNWFileMount)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(uint32(0), statT.UID()), "bind mounted network file should not change ownership from root")
|
||||
}
|
||||
|
||||
func TestMountDaemonRoot(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || testEnv.IsRemoteDaemon())
|
||||
t.Parallel()
|
||||
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
info, err := client.Info(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, test := range []struct {
|
||||
desc string
|
||||
propagation mount.Propagation
|
||||
expected mount.Propagation
|
||||
}{
|
||||
{
|
||||
desc: "default",
|
||||
propagation: "",
|
||||
expected: mount.PropagationRSlave,
|
||||
},
|
||||
{
|
||||
desc: "private",
|
||||
propagation: mount.PropagationPrivate,
|
||||
},
|
||||
{
|
||||
desc: "rprivate",
|
||||
propagation: mount.PropagationRPrivate,
|
||||
},
|
||||
{
|
||||
desc: "slave",
|
||||
propagation: mount.PropagationSlave,
|
||||
},
|
||||
{
|
||||
desc: "rslave",
|
||||
propagation: mount.PropagationRSlave,
|
||||
expected: mount.PropagationRSlave,
|
||||
},
|
||||
{
|
||||
desc: "shared",
|
||||
propagation: mount.PropagationShared,
|
||||
},
|
||||
{
|
||||
desc: "rshared",
|
||||
propagation: mount.PropagationRShared,
|
||||
expected: mount.PropagationRShared,
|
||||
},
|
||||
} {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
test := test
|
||||
t.Parallel()
|
||||
|
||||
propagationSpec := fmt.Sprintf(":%s", test.propagation)
|
||||
if test.propagation == "" {
|
||||
propagationSpec = ""
|
||||
}
|
||||
bindSpecRoot := info.DockerRootDir + ":" + "/foo" + propagationSpec
|
||||
bindSpecSub := filepath.Join(info.DockerRootDir, "containers") + ":/foo" + propagationSpec
|
||||
|
||||
for name, hc := range map[string]*container.HostConfig{
|
||||
"bind root": {Binds: []string{bindSpecRoot}},
|
||||
"bind subpath": {Binds: []string{bindSpecSub}},
|
||||
"mount root": {
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: mount.TypeBind,
|
||||
Source: info.DockerRootDir,
|
||||
Target: "/foo",
|
||||
BindOptions: &mount.BindOptions{Propagation: test.propagation},
|
||||
},
|
||||
},
|
||||
},
|
||||
"mount subpath": {
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: mount.TypeBind,
|
||||
Source: filepath.Join(info.DockerRootDir, "containers"),
|
||||
Target: "/foo",
|
||||
BindOptions: &mount.BindOptions{Propagation: test.propagation},
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
hc := hc
|
||||
t.Parallel()
|
||||
|
||||
c, err := client.ContainerCreate(ctx, &container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"true"},
|
||||
}, hc, nil, "")
|
||||
|
||||
if err != nil {
|
||||
if test.expected != "" {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// expected an error, so this is ok and should not continue
|
||||
return
|
||||
}
|
||||
if test.expected == "" {
|
||||
t.Fatal("expected create to fail")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := client.ContainerRemove(ctx, c.ID, types.ContainerRemoveOptions{Force: true}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, c.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(inspect.Mounts) != 1 {
|
||||
t.Fatalf("unexpected number of mounts: %+v", inspect.Mounts)
|
||||
}
|
||||
|
||||
m := inspect.Mounts[0]
|
||||
if m.Propagation != test.expected {
|
||||
t.Fatalf("got unexpected propagation mode, expected %q, got: %v", test.expected, m.Propagation)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
120
vendor/github.com/docker/docker-ce/components/engine/integration/container/nat_test.go
generated
vendored
Normal file
120
vendor/github.com/docker/docker-ce/components/engine/integration/container/nat_test.go
generated
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestNetworkNat(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
|
||||
msg := "it works"
|
||||
startServerContainer(t, msg, 8080)
|
||||
|
||||
endpoint := getExternalAddress(t)
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", endpoint.String(), 8080))
|
||||
assert.NilError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(conn)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(msg, strings.TrimSpace(string(data))))
|
||||
}
|
||||
|
||||
func TestNetworkLocalhostTCPNat(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
|
||||
msg := "hi yall"
|
||||
startServerContainer(t, msg, 8081)
|
||||
|
||||
conn, err := net.Dial("tcp", "localhost:8081")
|
||||
assert.NilError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(conn)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(msg, strings.TrimSpace(string(data))))
|
||||
}
|
||||
|
||||
func TestNetworkLoopbackNat(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
|
||||
msg := "it works"
|
||||
serverContainerID := startServerContainer(t, msg, 8080)
|
||||
|
||||
endpoint := getExternalAddress(t)
|
||||
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", fmt.Sprintf("stty raw && nc -w 5 %s 8080", endpoint.String())), container.WithTty(true), container.WithNetworkMode("container:"+serverContainerID))
|
||||
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
body, err := client.ContainerLogs(ctx, cID, types.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
defer body.Close()
|
||||
|
||||
var b bytes.Buffer
|
||||
_, err = io.Copy(&b, body)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, is.Equal(msg, strings.TrimSpace(b.String())))
|
||||
}
|
||||
|
||||
func startServerContainer(t *testing.T, msg string, port int) string {
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithName("server-"+t.Name()), container.WithCmd("sh", "-c", fmt.Sprintf("echo %q | nc -lp %d", msg, port)), container.WithExposedPorts(fmt.Sprintf("%d/tcp", port)), func(c *container.TestContainerConfig) {
|
||||
c.HostConfig.PortBindings = nat.PortMap{
|
||||
nat.Port(fmt.Sprintf("%d/tcp", port)): []nat.PortBinding{
|
||||
{
|
||||
HostPort: fmt.Sprintf("%d", port),
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
return cID
|
||||
}
|
||||
|
||||
func getExternalAddress(t *testing.T) net.IP {
|
||||
iface, err := net.InterfaceByName("eth0")
|
||||
skip.If(t, err != nil, "Test not running with `make test-integration`. Interface eth0 not found: %s", err)
|
||||
|
||||
ifaceAddrs, err := iface.Addrs()
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, 0 != len(ifaceAddrs))
|
||||
|
||||
ifaceIP, _, err := net.ParseCIDR(ifaceAddrs[0].String())
|
||||
assert.NilError(t, err)
|
||||
|
||||
return ifaceIP
|
||||
}
|
98
vendor/github.com/docker/docker-ce/components/engine/integration/container/pause_test.go
generated
vendored
Normal file
98
vendor/github.com/docker/docker-ce/components/engine/integration/container/pause_test.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestPause(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType == "windows" && testEnv.DaemonInfo.Isolation == "process")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
since := request.DaemonUnixTime(ctx, t, client, testEnv)
|
||||
|
||||
err := client.ContainerPause(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(true, inspect.State.Paused))
|
||||
|
||||
err = client.ContainerUnpause(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
until := request.DaemonUnixTime(ctx, t, client, testEnv)
|
||||
|
||||
messages, errs := client.Events(ctx, types.EventsOptions{
|
||||
Since: since,
|
||||
Until: until,
|
||||
Filters: filters.NewArgs(filters.Arg("container", cID)),
|
||||
})
|
||||
assert.Check(t, is.DeepEqual([]string{"pause", "unpause"}, getEventActions(t, messages, errs)))
|
||||
}
|
||||
|
||||
func TestPauseFailsOnWindowsServerContainers(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "windows" || testEnv.DaemonInfo.Isolation != "process")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerPause(ctx, cID)
|
||||
assert.Check(t, is.ErrorContains(err, "cannot pause Windows Server Containers"))
|
||||
}
|
||||
|
||||
func TestPauseStopPausedContainer(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.31"), "broken in earlier versions")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerPause(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.ContainerStop(ctx, cID, nil)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
||||
func getEventActions(t *testing.T, messages <-chan events.Message, errs <-chan error) []string {
|
||||
var actions []string
|
||||
for {
|
||||
select {
|
||||
case err := <-errs:
|
||||
assert.Check(t, err == nil || err == io.EOF)
|
||||
return actions
|
||||
case e := <-messages:
|
||||
actions = append(actions, e.Status)
|
||||
}
|
||||
}
|
||||
}
|
49
vendor/github.com/docker/docker-ce/components/engine/integration/container/ps_test.go
generated
vendored
Normal file
49
vendor/github.com/docker/docker-ce/components/engine/integration/container/ps_test.go
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func TestPsFilter(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
prev := container.Create(t, ctx, client)
|
||||
top := container.Create(t, ctx, client)
|
||||
next := container.Create(t, ctx, client)
|
||||
|
||||
containerIDs := func(containers []types.Container) []string {
|
||||
var entries []string
|
||||
for _, container := range containers {
|
||||
entries = append(entries, container.ID)
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
f1 := filters.NewArgs()
|
||||
f1.Add("since", top)
|
||||
q1, err := client.ContainerList(ctx, types.ContainerListOptions{
|
||||
All: true,
|
||||
Filters: f1,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(containerIDs(q1), next))
|
||||
|
||||
f2 := filters.NewArgs()
|
||||
f2.Add("before", top)
|
||||
q2, err := client.ContainerList(ctx, types.ContainerListOptions{
|
||||
All: true,
|
||||
Filters: f2,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(containerIDs(q2), prev))
|
||||
}
|
112
vendor/github.com/docker/docker-ce/components/engine/integration/container/remove_test.go
generated
vendored
Normal file
112
vendor/github.com/docker/docker-ce/components/engine/integration/container/remove_test.go
generated
vendored
Normal file
|
@ -0,0 +1,112 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/fs"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) {
|
||||
if testEnv.OSType == "windows" {
|
||||
return "c:", `\`
|
||||
}
|
||||
return "", "/"
|
||||
}
|
||||
|
||||
// Test case for #5244: `docker rm` fails if bind dir doesn't exist anymore
|
||||
func TestRemoveContainerWithRemovedVolume(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
tempDir := fs.NewDir(t, "test-rm-container-with-removed-volume", fs.WithMode(0755))
|
||||
defer tempDir.Remove()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("true"), container.WithBind(tempDir.Path(), prefix+slash+"test"))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := os.RemoveAll(tempDir.Path())
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{
|
||||
RemoveVolumes: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, _, err = client.ContainerInspectWithRaw(ctx, cID, true)
|
||||
assert.Check(t, is.ErrorContains(err, "No such container"))
|
||||
}
|
||||
|
||||
// Test case for #2099/#2125
|
||||
func TestRemoveContainerWithVolume(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("true"), container.WithVolume(prefix+slash+"srv"))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
insp, _, err := client.ContainerInspectWithRaw(ctx, cID, true)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(1, len(insp.Mounts)))
|
||||
volName := insp.Mounts[0].Name
|
||||
|
||||
err = client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{
|
||||
RemoveVolumes: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
volumes, err := client.VolumeList(ctx, filters.NewArgs(filters.Arg("name", volName)))
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(0, len(volumes.Volumes)))
|
||||
}
|
||||
|
||||
func TestRemoveContainerRunning(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
err := client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{})
|
||||
assert.Check(t, is.ErrorContains(err, "cannot remove a running container"))
|
||||
}
|
||||
|
||||
func TestRemoveContainerForceRemoveRunning(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
err := client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{
|
||||
Force: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestRemoveInvalidContainer(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
err := client.ContainerRemove(ctx, "unknown", types.ContainerRemoveOptions{})
|
||||
assert.Check(t, is.ErrorContains(err, "No such container"))
|
||||
}
|
213
vendor/github.com/docker/docker-ce/components/engine/integration/container/rename_test.go
generated
vendored
Normal file
213
vendor/github.com/docker/docker-ce/components/engine/integration/container/rename_test.go
generated
vendored
Normal file
|
@ -0,0 +1,213 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
// This test simulates the scenario mentioned in #31392:
|
||||
// Having two linked container, renaming the target and bringing a replacement
|
||||
// and then deleting and recreating the source container linked to the new target.
|
||||
// This checks that "rename" updates source container correctly and doesn't set it to null.
|
||||
func TestRenameLinkedContainer(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.32"), "broken in earlier versions")
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
aName := "a0" + t.Name()
|
||||
bName := "b0" + t.Name()
|
||||
aID := container.Run(t, ctx, client, container.WithName(aName))
|
||||
bID := container.Run(t, ctx, client, container.WithName(bName), container.WithLinks(aName))
|
||||
|
||||
err := client.ContainerRename(ctx, aID, "a1"+t.Name())
|
||||
assert.NilError(t, err)
|
||||
|
||||
container.Run(t, ctx, client, container.WithName(aName))
|
||||
|
||||
err = client.ContainerRemove(ctx, bID, types.ContainerRemoveOptions{Force: true})
|
||||
assert.NilError(t, err)
|
||||
|
||||
bID = container.Run(t, ctx, client, container.WithName(bName), container.WithLinks(aName))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, bID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual([]string{"/" + aName + ":/" + bName + "/" + aName}, inspect.HostConfig.Links))
|
||||
}
|
||||
|
||||
func TestRenameStoppedContainer(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
oldName := "first_name" + t.Name()
|
||||
cID := container.Run(t, ctx, client, container.WithName(oldName), container.WithCmd("sh"))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal("/"+oldName, inspect.Name))
|
||||
|
||||
newName := "new_name" + stringid.GenerateNonCryptoID()
|
||||
err = client.ContainerRename(ctx, oldName, newName)
|
||||
assert.NilError(t, err)
|
||||
|
||||
inspect, err = client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal("/"+newName, inspect.Name))
|
||||
}
|
||||
|
||||
func TestRenameRunningContainerAndReuse(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
oldName := "first_name" + t.Name()
|
||||
cID := container.Run(t, ctx, client, container.WithName(oldName))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
newName := "new_name" + stringid.GenerateNonCryptoID()
|
||||
err := client.ContainerRename(ctx, oldName, newName)
|
||||
assert.NilError(t, err)
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal("/"+newName, inspect.Name))
|
||||
|
||||
_, err = client.ContainerInspect(ctx, oldName)
|
||||
assert.Check(t, is.ErrorContains(err, "No such container: "+oldName))
|
||||
|
||||
cID = container.Run(t, ctx, client, container.WithName(oldName))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
inspect, err = client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal("/"+oldName, inspect.Name))
|
||||
}
|
||||
|
||||
func TestRenameInvalidName(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
oldName := "first_name" + t.Name()
|
||||
cID := container.Run(t, ctx, client, container.WithName(oldName))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerRename(ctx, oldName, "new:invalid")
|
||||
assert.Check(t, is.ErrorContains(err, "Invalid container name"))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, oldName)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(cID, inspect.ID))
|
||||
}
|
||||
|
||||
// Test case for GitHub issue 22466
|
||||
// Docker's service discovery works for named containers so
|
||||
// ping to a named container should work, and an anonymous
|
||||
// container without a name does not work with service discovery.
|
||||
// However, an anonymous could be renamed to a named container.
|
||||
// This test is to make sure once the container has been renamed,
|
||||
// the service discovery for the (re)named container works.
|
||||
func TestRenameAnonymousContainer(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
networkName := "network1" + t.Name()
|
||||
_, err := client.NetworkCreate(ctx, networkName, types.NetworkCreate{})
|
||||
|
||||
assert.NilError(t, err)
|
||||
cID := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
|
||||
c.NetworkingConfig.EndpointsConfig = map[string]*network.EndpointSettings{
|
||||
networkName: {},
|
||||
}
|
||||
c.HostConfig.NetworkMode = containertypes.NetworkMode(networkName)
|
||||
})
|
||||
|
||||
container1Name := "container1" + t.Name()
|
||||
err = client.ContainerRename(ctx, cID, container1Name)
|
||||
assert.NilError(t, err)
|
||||
// Stop/Start the container to get registered
|
||||
// FIXME(vdemeester) this is a really weird behavior as it fails otherwise
|
||||
err = client.ContainerStop(ctx, container1Name, nil)
|
||||
assert.NilError(t, err)
|
||||
err = client.ContainerStart(ctx, container1Name, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
count := "-c"
|
||||
if testEnv.OSType == "windows" {
|
||||
count = "-n"
|
||||
}
|
||||
cID = container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
|
||||
c.NetworkingConfig.EndpointsConfig = map[string]*network.EndpointSettings{
|
||||
networkName: {},
|
||||
}
|
||||
c.HostConfig.NetworkMode = containertypes.NetworkMode(networkName)
|
||||
}, container.WithCmd("ping", count, "1", container1Name))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(0, inspect.State.ExitCode), "container %s exited with the wrong exitcode: %+v", cID, inspect)
|
||||
}
|
||||
|
||||
// TODO: should be a unit test
|
||||
func TestRenameContainerWithSameName(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
oldName := "old" + t.Name()
|
||||
cID := container.Run(t, ctx, client, container.WithName(oldName))
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
err := client.ContainerRename(ctx, oldName, oldName)
|
||||
assert.Check(t, is.ErrorContains(err, "Renaming a container with the same name"))
|
||||
err = client.ContainerRename(ctx, cID, oldName)
|
||||
assert.Check(t, is.ErrorContains(err, "Renaming a container with the same name"))
|
||||
}
|
||||
|
||||
// Test case for GitHub issue 23973
|
||||
// When a container is being renamed, the container might
|
||||
// be linked to another container. In that case, the meta data
|
||||
// of the linked container should be updated so that the other
|
||||
// container could still reference to the container that is renamed.
|
||||
func TestRenameContainerWithLinkedContainer(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
db1Name := "db1" + t.Name()
|
||||
db1ID := container.Run(t, ctx, client, container.WithName(db1Name))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, db1ID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
app1Name := "app1" + t.Name()
|
||||
app2Name := "app2" + t.Name()
|
||||
app1ID := container.Run(t, ctx, client, container.WithName(app1Name), container.WithLinks(db1Name+":/mysql"))
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, app1ID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerRename(ctx, app1Name, app2Name)
|
||||
assert.NilError(t, err)
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, app2Name+"/mysql")
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(db1ID, inspect.ID))
|
||||
}
|
66
vendor/github.com/docker/docker-ce/components/engine/integration/container/resize_test.go
generated
vendored
Normal file
66
vendor/github.com/docker/docker-ce/components/engine/integration/container/resize_test.go
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
req "github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestResize(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerResize(ctx, cID, types.ResizeOptions{
|
||||
Height: 40,
|
||||
Width: 40,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestResizeWithInvalidSize(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.32"), "broken in earlier versions")
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
endpoint := "/containers/" + cID + "/resize?h=foo&w=bar"
|
||||
res, _, err := req.Post(endpoint)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(http.StatusBadRequest, res.StatusCode))
|
||||
}
|
||||
|
||||
func TestResizeWhenContainerNotStarted(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("echo"))
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
err := client.ContainerResize(ctx, cID, types.ResizeOptions{
|
||||
Height: 40,
|
||||
Width: 40,
|
||||
})
|
||||
assert.Check(t, is.ErrorContains(err, "is not running"))
|
||||
}
|
114
vendor/github.com/docker/docker-ce/components/engine/integration/container/restart_test.go
generated
vendored
Normal file
114
vendor/github.com/docker/docker-ce/components/engine/integration/container/restart_test.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestDaemonRestartKillContainers(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run")
|
||||
type testCase struct {
|
||||
desc string
|
||||
config *container.Config
|
||||
hostConfig *container.HostConfig
|
||||
|
||||
xRunning bool
|
||||
xRunningLiveRestore bool
|
||||
xStart bool
|
||||
}
|
||||
|
||||
for _, c := range []testCase{
|
||||
{
|
||||
desc: "container without restart policy",
|
||||
config: &container.Config{Image: "busybox", Cmd: []string{"top"}},
|
||||
xRunningLiveRestore: true,
|
||||
xStart: true,
|
||||
},
|
||||
{
|
||||
desc: "container with restart=always",
|
||||
config: &container.Config{Image: "busybox", Cmd: []string{"top"}},
|
||||
hostConfig: &container.HostConfig{RestartPolicy: container.RestartPolicy{Name: "always"}},
|
||||
xRunning: true,
|
||||
xRunningLiveRestore: true,
|
||||
xStart: true,
|
||||
},
|
||||
{
|
||||
desc: "container created should not be restarted",
|
||||
config: &container.Config{Image: "busybox", Cmd: []string{"top"}},
|
||||
hostConfig: &container.HostConfig{RestartPolicy: container.RestartPolicy{Name: "always"}},
|
||||
},
|
||||
} {
|
||||
for _, liveRestoreEnabled := range []bool{false, true} {
|
||||
for fnName, stopDaemon := range map[string]func(*testing.T, *daemon.Daemon){
|
||||
"kill-daemon": func(t *testing.T, d *daemon.Daemon) {
|
||||
err := d.Kill()
|
||||
assert.NilError(t, err)
|
||||
},
|
||||
"stop-daemon": func(t *testing.T, d *daemon.Daemon) {
|
||||
d.Stop(t)
|
||||
},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("live-restore=%v/%s/%s", liveRestoreEnabled, c.desc, fnName), func(t *testing.T) {
|
||||
c := c
|
||||
liveRestoreEnabled := liveRestoreEnabled
|
||||
stopDaemon := stopDaemon
|
||||
|
||||
t.Parallel()
|
||||
|
||||
d := daemon.New(t)
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
args := []string{"--iptables=false"}
|
||||
if liveRestoreEnabled {
|
||||
args = append(args, "--live-restore")
|
||||
}
|
||||
|
||||
d.StartWithBusybox(t, args...)
|
||||
defer d.Stop(t)
|
||||
ctx := context.Background()
|
||||
|
||||
resp, err := client.ContainerCreate(ctx, c.config, c.hostConfig, nil, "")
|
||||
assert.NilError(t, err)
|
||||
defer client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
if c.xStart {
|
||||
err = client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
stopDaemon(t, d)
|
||||
d.Start(t, args...)
|
||||
|
||||
expected := c.xRunning
|
||||
if liveRestoreEnabled {
|
||||
expected = c.xRunningLiveRestore
|
||||
}
|
||||
|
||||
var running bool
|
||||
for i := 0; i < 30; i++ {
|
||||
inspect, err := client.ContainerInspect(ctx, resp.ID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
running = inspect.State.Running
|
||||
if running == expected {
|
||||
break
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
}
|
||||
assert.Equal(t, expected, running, "got unexpected running state, expected %v, got: %v", expected, running)
|
||||
// TODO(cpuguy83): test pause states... this seems to be rather undefined currently
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
vendor/github.com/docker/docker-ce/components/engine/integration/container/stats_test.go
generated
vendored
Normal file
43
vendor/github.com/docker/docker-ce/components/engine/integration/container/stats_test.go
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestStats(t *testing.T) {
|
||||
skip.If(t, !testEnv.DaemonInfo.MemoryLimit)
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
info, err := client.Info(ctx)
|
||||
assert.NilError(t, err)
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
resp, err := client.ContainerStats(ctx, cID, false)
|
||||
assert.NilError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
var v *types.Stats
|
||||
err = json.NewDecoder(resp.Body).Decode(&v)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(int64(v.MemoryStats.Limit), info.MemTotal))
|
||||
err = json.NewDecoder(resp.Body).Decode(&v)
|
||||
assert.Assert(t, is.ErrorContains(err, ""), io.EOF)
|
||||
}
|
127
vendor/github.com/docker/docker-ce/components/engine/integration/container/stop_test.go
generated
vendored
Normal file
127
vendor/github.com/docker/docker-ce/components/engine/integration/container/stop_test.go
generated
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/icmd"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestStopContainerWithRestartPolicyAlways(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
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"
|
||||
})
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, name, "running", "restarting"), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
err := client.ContainerStop(ctx, name, nil)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, name), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
}
|
||||
|
||||
// TestStopContainerWithTimeout checks that ContainerStop with
|
||||
// a timeout works as documented, i.e. in case of negative timeout
|
||||
// waiting is not limited (issue #35311).
|
||||
func TestStopContainerWithTimeout(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
testCmd := container.WithCmd("sh", "-c", "sleep 2 && exit 42")
|
||||
testData := []struct {
|
||||
doc string
|
||||
timeout int
|
||||
expectedExitCode int
|
||||
}{
|
||||
// In case container is forcefully killed, 137 is returned,
|
||||
// otherwise the exit code from the above script
|
||||
{
|
||||
"zero timeout: expect forceful container kill",
|
||||
0, 137,
|
||||
},
|
||||
{
|
||||
"too small timeout: expect forceful container kill",
|
||||
1, 137,
|
||||
},
|
||||
{
|
||||
"big enough timeout: expect graceful container stop",
|
||||
3, 42,
|
||||
},
|
||||
{
|
||||
"unlimited timeout: expect graceful container stop",
|
||||
-1, 42,
|
||||
},
|
||||
}
|
||||
|
||||
for _, d := range testData {
|
||||
d := d
|
||||
t.Run(strconv.Itoa(d.timeout), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
id := container.Run(t, ctx, client, testCmd)
|
||||
|
||||
timeout := time.Duration(d.timeout) * time.Second
|
||||
err := client.ContainerStop(ctx, id, &timeout)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, container.IsStopped(ctx, client, id),
|
||||
poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, id)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, inspect.State.ExitCode, d.expectedExitCode)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteDevicemapper(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.Driver != "devicemapper")
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
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))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, id)
|
||||
assert.NilError(t, err)
|
||||
|
||||
deviceID := inspect.GraphDriver.Data["DeviceId"]
|
||||
|
||||
// Find pool name from device name
|
||||
deviceName := inspect.GraphDriver.Data["DeviceName"]
|
||||
devicePrefix := deviceName[:strings.LastIndex(deviceName, "-")]
|
||||
devicePool := fmt.Sprintf("/dev/mapper/%s-pool", devicePrefix)
|
||||
|
||||
result := icmd.RunCommand("dmsetup", "message", devicePool, "0", fmt.Sprintf("delete %s", deviceID))
|
||||
result.Assert(t, icmd.Success)
|
||||
|
||||
err = client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
}
|
107
vendor/github.com/docker/docker-ce/components/engine/integration/container/update_linux_test.go
generated
vendored
Normal file
107
vendor/github.com/docker/docker-ce/components/engine/integration/container/update_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestUpdateMemory(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
skip.If(t, !testEnv.DaemonInfo.MemoryLimit)
|
||||
skip.If(t, !testEnv.DaemonInfo.SwapLimit)
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
|
||||
c.HostConfig.Resources = containertypes.Resources{
|
||||
Memory: 200 * 1024 * 1024,
|
||||
}
|
||||
})
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
|
||||
|
||||
const (
|
||||
setMemory int64 = 314572800
|
||||
setMemorySwap int64 = 524288000
|
||||
)
|
||||
|
||||
_, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
|
||||
Resources: containertypes.Resources{
|
||||
Memory: setMemory,
|
||||
MemorySwap: setMemorySwap,
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(setMemory, inspect.HostConfig.Memory))
|
||||
assert.Check(t, is.Equal(setMemorySwap, inspect.HostConfig.MemorySwap))
|
||||
|
||||
res, err := container.Exec(ctx, client, cID,
|
||||
[]string{"cat", "/sys/fs/cgroup/memory/memory.limit_in_bytes"})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, is.Len(res.Stderr(), 0))
|
||||
assert.Equal(t, 0, res.ExitCode)
|
||||
assert.Check(t, is.Equal(strconv.FormatInt(setMemory, 10), strings.TrimSpace(res.Stdout())))
|
||||
|
||||
res, err = container.Exec(ctx, client, cID,
|
||||
[]string{"cat", "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, is.Len(res.Stderr(), 0))
|
||||
assert.Equal(t, 0, res.ExitCode)
|
||||
assert.Check(t, is.Equal(strconv.FormatInt(setMemorySwap, 10), strings.TrimSpace(res.Stdout())))
|
||||
}
|
||||
|
||||
func TestUpdateCPUQuota(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
for _, test := range []struct {
|
||||
desc string
|
||||
update int64
|
||||
}{
|
||||
{desc: "some random value", update: 15000},
|
||||
{desc: "a higher value", update: 20000},
|
||||
{desc: "a lower value", update: 10000},
|
||||
{desc: "unset value", update: -1},
|
||||
} {
|
||||
if _, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
|
||||
Resources: containertypes.Resources{
|
||||
CPUQuota: test.update,
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(test.update, inspect.HostConfig.CPUQuota))
|
||||
|
||||
res, err := container.Exec(ctx, client, cID,
|
||||
[]string{"/bin/cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, is.Len(res.Stderr(), 0))
|
||||
assert.Equal(t, 0, res.ExitCode)
|
||||
|
||||
assert.Check(t, is.Equal(strconv.FormatInt(test.update, 10), strings.TrimSpace(res.Stdout())))
|
||||
}
|
||||
}
|
64
vendor/github.com/docker/docker-ce/components/engine/integration/container/update_test.go
generated
vendored
Normal file
64
vendor/github.com/docker/docker-ce/components/engine/integration/container/update_test.go
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
)
|
||||
|
||||
func TestUpdateRestartPolicy(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", "sleep 1 && false"), func(c *container.TestContainerConfig) {
|
||||
c.HostConfig.RestartPolicy = containertypes.RestartPolicy{
|
||||
Name: "on-failure",
|
||||
MaximumRetryCount: 3,
|
||||
}
|
||||
})
|
||||
|
||||
_, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
|
||||
RestartPolicy: containertypes.RestartPolicy{
|
||||
Name: "on-failure",
|
||||
MaximumRetryCount: 5,
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
timeout := 60 * time.Second
|
||||
if testEnv.OSType == "windows" {
|
||||
timeout = 180 * time.Second
|
||||
}
|
||||
|
||||
poll.WaitOn(t, container.IsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond), poll.WithTimeout(timeout))
|
||||
|
||||
inspect, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(inspect.RestartCount, 5))
|
||||
assert.Check(t, is.Equal(inspect.HostConfig.RestartPolicy.MaximumRetryCount, 5))
|
||||
}
|
||||
|
||||
func TestUpdateRestartWithAutoRemove(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
|
||||
c.HostConfig.AutoRemove = true
|
||||
})
|
||||
|
||||
_, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
|
||||
RestartPolicy: containertypes.RestartPolicy{
|
||||
Name: "always",
|
||||
},
|
||||
})
|
||||
assert.Check(t, is.ErrorContains(err, "Restart policy cannot be updated because AutoRemove is enabled for the container"))
|
||||
}
|
3
vendor/github.com/docker/docker-ce/components/engine/integration/doc.go
generated
vendored
Normal file
3
vendor/github.com/docker/docker-ce/components/engine/integration/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
// Package integration provides integrations tests for Moby (API).
|
||||
// These tests require a daemon (dockerd for now) to run.
|
||||
package integration // import "github.com/docker/docker/integration"
|
48
vendor/github.com/docker/docker-ce/components/engine/integration/image/commit_test.go
generated
vendored
Normal file
48
vendor/github.com/docker/docker-ce/components/engine/integration/image/commit_test.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
package image // import "github.com/docker/docker/integration/image"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestCommitInheritsEnv(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.36"), "broken in earlier versions")
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
cID1 := container.Create(t, ctx, client)
|
||||
|
||||
commitResp1, err := client.ContainerCommit(ctx, cID1, types.ContainerCommitOptions{
|
||||
Changes: []string{"ENV PATH=/bin"},
|
||||
Reference: "test-commit-image",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
image1, _, err := client.ImageInspectWithRaw(ctx, commitResp1.ID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
expectedEnv1 := []string{"PATH=/bin"}
|
||||
assert.Check(t, is.DeepEqual(expectedEnv1, image1.Config.Env))
|
||||
|
||||
cID2 := container.Create(t, ctx, client, container.WithImage(image1.ID))
|
||||
|
||||
commitResp2, err := client.ContainerCommit(ctx, cID2, types.ContainerCommitOptions{
|
||||
Changes: []string{"ENV PATH=/usr/bin:$PATH"},
|
||||
Reference: "test-commit-image",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
image2, _, err := client.ImageInspectWithRaw(ctx, commitResp2.ID)
|
||||
assert.NilError(t, err)
|
||||
expectedEnv2 := []string{"PATH=/usr/bin:/bin"}
|
||||
assert.Check(t, is.DeepEqual(expectedEnv2, image2.Config.Env))
|
||||
}
|
42
vendor/github.com/docker/docker-ce/components/engine/integration/image/import_test.go
generated
vendored
Normal file
42
vendor/github.com/docker/docker-ce/components/engine/integration/image/import_test.go
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
package image // import "github.com/docker/docker/integration/image"
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/internal/testutil"
|
||||
)
|
||||
|
||||
// Ensure we don't regress on CVE-2017-14992.
|
||||
func TestImportExtremelyLargeImageWorks(t *testing.T) {
|
||||
if runtime.GOARCH == "arm64" {
|
||||
t.Skip("effective test will be time out")
|
||||
}
|
||||
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
// Construct an empty tar archive with about 8GB of junk padding at the
|
||||
// end. This should not cause any crashes (the padding should be mostly
|
||||
// ignored).
|
||||
var tarBuffer bytes.Buffer
|
||||
|
||||
tw := tar.NewWriter(&tarBuffer)
|
||||
if err := tw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
imageRdr := io.MultiReader(&tarBuffer, io.LimitReader(testutil.DevZero, 8*1024*1024*1024))
|
||||
|
||||
_, err := client.ImageImport(context.Background(),
|
||||
types.ImageImportSource{Source: imageRdr, SourceName: "-"},
|
||||
"test1234:v42",
|
||||
types.ImageImportOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/image/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/image/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package image // import "github.com/docker/docker/integration/image"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
59
vendor/github.com/docker/docker-ce/components/engine/integration/image/remove_test.go
generated
vendored
Normal file
59
vendor/github.com/docker/docker-ce/components/engine/integration/image/remove_test.go
generated
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
package image // import "github.com/docker/docker/integration/image"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func TestRemoveImageOrphaning(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
img := "test-container-orphaning"
|
||||
|
||||
// Create a container from busybox, and commit a small change so we have a new image
|
||||
cID1 := container.Create(t, ctx, client, container.WithCmd(""))
|
||||
commitResp1, err := client.ContainerCommit(ctx, cID1, types.ContainerCommitOptions{
|
||||
Changes: []string{`ENTRYPOINT ["true"]`},
|
||||
Reference: img,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// verifies that reference now points to first image
|
||||
resp, _, err := client.ImageInspectWithRaw(ctx, img)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(resp.ID, commitResp1.ID))
|
||||
|
||||
// Create a container from created image, and commit a small change with same reference name
|
||||
cID2 := container.Create(t, ctx, client, container.WithImage(img), container.WithCmd(""))
|
||||
commitResp2, err := client.ContainerCommit(ctx, cID2, types.ContainerCommitOptions{
|
||||
Changes: []string{`LABEL Maintainer="Integration Tests"`},
|
||||
Reference: img,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// verifies that reference now points to second image
|
||||
resp, _, err = client.ImageInspectWithRaw(ctx, img)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(resp.ID, commitResp2.ID))
|
||||
|
||||
// try to remove the image, should not error out.
|
||||
_, err = client.ImageRemove(ctx, img, types.ImageRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// check if the first image is still there
|
||||
resp, _, err = client.ImageInspectWithRaw(ctx, commitResp1.ID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(resp.ID, commitResp1.ID))
|
||||
|
||||
// check if the second image has been deleted
|
||||
_, _, err = client.ImageInspectWithRaw(ctx, commitResp2.ID)
|
||||
assert.Check(t, is.ErrorContains(err, "No such image:"))
|
||||
}
|
140
vendor/github.com/docker/docker-ce/components/engine/integration/image/tag_test.go
generated
vendored
Normal file
140
vendor/github.com/docker/docker-ce/components/engine/integration/image/tag_test.go
generated
vendored
Normal file
|
@ -0,0 +1,140 @@
|
|||
package image // import "github.com/docker/docker/integration/image"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/internal/testutil"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
// tagging a named image in a new unprefixed repo should work
|
||||
func TestTagUnprefixedRepoByNameOrName(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
// By name
|
||||
err := client.ImageTag(ctx, "busybox:latest", "testfoobarbaz")
|
||||
assert.NilError(t, err)
|
||||
|
||||
// By ID
|
||||
insp, _, err := client.ImageInspectWithRaw(ctx, "busybox")
|
||||
assert.NilError(t, err)
|
||||
err = client.ImageTag(ctx, insp.ID, "testfoobarbaz")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
// ensure we don't allow the use of invalid repository names or tags; these tag operations should fail
|
||||
// TODO (yongtang): Migrate to unit tests
|
||||
func TestTagInvalidReference(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
invalidRepos := []string{"fo$z$", "Foo@3cc", "Foo$3", "Foo*3", "Fo^3", "Foo!3", "F)xcz(", "fo%asd", "FOO/bar"}
|
||||
|
||||
for _, repo := range invalidRepos {
|
||||
err := client.ImageTag(ctx, "busybox", repo)
|
||||
assert.Check(t, is.ErrorContains(err, "not a valid repository/tag"))
|
||||
}
|
||||
|
||||
longTag := testutil.GenerateRandomAlphaOnlyString(121)
|
||||
|
||||
invalidTags := []string{"repo:fo$z$", "repo:Foo@3cc", "repo:Foo$3", "repo:Foo*3", "repo:Fo^3", "repo:Foo!3", "repo:%goodbye", "repo:#hashtagit", "repo:F)xcz(", "repo:-foo", "repo:..", longTag}
|
||||
|
||||
for _, repotag := range invalidTags {
|
||||
err := client.ImageTag(ctx, "busybox", repotag)
|
||||
assert.Check(t, is.ErrorContains(err, "not a valid repository/tag"))
|
||||
}
|
||||
|
||||
// test repository name begin with '-'
|
||||
err := client.ImageTag(ctx, "busybox:latest", "-busybox:test")
|
||||
assert.Check(t, is.ErrorContains(err, "Error parsing reference"))
|
||||
|
||||
// test namespace name begin with '-'
|
||||
err = client.ImageTag(ctx, "busybox:latest", "-test/busybox:test")
|
||||
assert.Check(t, is.ErrorContains(err, "Error parsing reference"))
|
||||
|
||||
// test index name begin with '-'
|
||||
err = client.ImageTag(ctx, "busybox:latest", "-index:5000/busybox:test")
|
||||
assert.Check(t, is.ErrorContains(err, "Error parsing reference"))
|
||||
|
||||
// test setting tag fails
|
||||
err = client.ImageTag(ctx, "busybox:latest", "sha256:sometag")
|
||||
assert.Check(t, is.ErrorContains(err, "refusing to create an ambiguous tag using digest algorithm as name"))
|
||||
}
|
||||
|
||||
// ensure we allow the use of valid tags
|
||||
func TestTagValidPrefixedRepo(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
validRepos := []string{"fooo/bar", "fooaa/test", "foooo:t", "HOSTNAME.DOMAIN.COM:443/foo/bar"}
|
||||
|
||||
for _, repo := range validRepos {
|
||||
err := client.ImageTag(ctx, "busybox", repo)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// tag an image with an existed tag name without -f option should work
|
||||
func TestTagExistedNameWithoutForce(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
err := client.ImageTag(ctx, "busybox:latest", "busybox:test")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
// ensure tagging using official names works
|
||||
// ensure all tags result in the same name
|
||||
func TestTagOfficialNames(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
names := []string{
|
||||
"docker.io/busybox",
|
||||
"index.docker.io/busybox",
|
||||
"library/busybox",
|
||||
"docker.io/library/busybox",
|
||||
"index.docker.io/library/busybox",
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
err := client.ImageTag(ctx, "busybox", name+":latest")
|
||||
assert.NilError(t, err)
|
||||
|
||||
// ensure we don't have multiple tag names.
|
||||
insp, _, err := client.ImageInspectWithRaw(ctx, "busybox")
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, !is.Contains(insp.RepoTags, name)().Success())
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
err := client.ImageTag(ctx, name+":latest", "fooo/bar:latest")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// ensure tags can not match digests
|
||||
func TestTagMatchesDigest(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
digest := "busybox@sha256:abcdef76720241213f5303bda7704ec4c2ef75613173910a56fb1b6e20251507"
|
||||
// test setting tag fails
|
||||
err := client.ImageTag(ctx, "busybox:latest", digest)
|
||||
assert.Check(t, is.ErrorContains(err, "refusing to create a tag with a digest reference"))
|
||||
|
||||
// check that no new image matches the digest
|
||||
_, _, err = client.ImageInspectWithRaw(ctx, digest)
|
||||
assert.Check(t, is.ErrorContains(err, fmt.Sprintf("No such image: %s", digest)))
|
||||
}
|
56
vendor/github.com/docker/docker-ce/components/engine/integration/internal/container/container.go
generated
vendored
Normal file
56
vendor/github.com/docker/docker-ce/components/engine/integration/internal/container/container.go
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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/client"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
// TestContainerConfig holds container configuration struct that
|
||||
// are used in api calls.
|
||||
type TestContainerConfig struct {
|
||||
Name string
|
||||
Config *container.Config
|
||||
HostConfig *container.HostConfig
|
||||
NetworkingConfig *network.NetworkingConfig
|
||||
}
|
||||
|
||||
// Create creates a container with the specified options
|
||||
// nolint: golint
|
||||
func Create(t *testing.T, ctx context.Context, client client.APIClient, ops ...func(*TestContainerConfig)) string { // nolint: golint
|
||||
t.Helper()
|
||||
config := &TestContainerConfig{
|
||||
Config: &container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"top"},
|
||||
},
|
||||
HostConfig: &container.HostConfig{},
|
||||
NetworkingConfig: &network.NetworkingConfig{},
|
||||
}
|
||||
|
||||
for _, op := range ops {
|
||||
op(config)
|
||||
}
|
||||
|
||||
c, err := client.ContainerCreate(ctx, config.Config, config.HostConfig, config.NetworkingConfig, config.Name)
|
||||
assert.NilError(t, err)
|
||||
|
||||
return c.ID
|
||||
}
|
||||
|
||||
// Run creates and start a container with the specified options
|
||||
// nolint: golint
|
||||
func Run(t *testing.T, ctx context.Context, client client.APIClient, ops ...func(*TestContainerConfig)) string { // nolint: golint
|
||||
t.Helper()
|
||||
id := Create(t, ctx, client, ops...)
|
||||
|
||||
err := client.ContainerStart(ctx, id, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
return id
|
||||
}
|
86
vendor/github.com/docker/docker-ce/components/engine/integration/internal/container/exec.go
generated
vendored
Normal file
86
vendor/github.com/docker/docker-ce/components/engine/integration/internal/container/exec.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
)
|
||||
|
||||
// ExecResult represents a result returned from Exec()
|
||||
type ExecResult struct {
|
||||
ExitCode int
|
||||
outBuffer *bytes.Buffer
|
||||
errBuffer *bytes.Buffer
|
||||
}
|
||||
|
||||
// Stdout returns stdout output of a command run by Exec()
|
||||
func (res *ExecResult) Stdout() string {
|
||||
return res.outBuffer.String()
|
||||
}
|
||||
|
||||
// Stderr returns stderr output of a command run by Exec()
|
||||
func (res *ExecResult) Stderr() string {
|
||||
return res.errBuffer.String()
|
||||
}
|
||||
|
||||
// Combined returns combined stdout and stderr output of a command run by Exec()
|
||||
func (res *ExecResult) Combined() string {
|
||||
return res.outBuffer.String() + res.errBuffer.String()
|
||||
}
|
||||
|
||||
// Exec executes a command inside a container, returning the result
|
||||
// containing stdout, stderr, and exit code. Note:
|
||||
// - this is a synchronous operation;
|
||||
// - cmd stdin is closed.
|
||||
func Exec(ctx context.Context, cli client.APIClient, id string, cmd []string) (ExecResult, error) {
|
||||
// prepare exec
|
||||
execConfig := types.ExecConfig{
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Cmd: cmd,
|
||||
}
|
||||
cresp, err := cli.ContainerExecCreate(ctx, id, execConfig)
|
||||
if err != nil {
|
||||
return ExecResult{}, err
|
||||
}
|
||||
execID := cresp.ID
|
||||
|
||||
// run it, with stdout/stderr attached
|
||||
aresp, err := cli.ContainerExecAttach(ctx, execID, types.ExecStartCheck{})
|
||||
if err != nil {
|
||||
return ExecResult{}, err
|
||||
}
|
||||
defer aresp.Close()
|
||||
|
||||
// read the output
|
||||
var outBuf, errBuf bytes.Buffer
|
||||
outputDone := make(chan error)
|
||||
|
||||
go func() {
|
||||
// StdCopy demultiplexes the stream into two buffers
|
||||
_, err = stdcopy.StdCopy(&outBuf, &errBuf, aresp.Reader)
|
||||
outputDone <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-outputDone:
|
||||
if err != nil {
|
||||
return ExecResult{}, err
|
||||
}
|
||||
break
|
||||
|
||||
case <-ctx.Done():
|
||||
return ExecResult{}, ctx.Err()
|
||||
}
|
||||
|
||||
// get the exit code
|
||||
iresp, err := cli.ContainerExecInspect(ctx, execID)
|
||||
if err != nil {
|
||||
return ExecResult{}, err
|
||||
}
|
||||
|
||||
return ExecResult{ExitCode: iresp.ExitCode, outBuffer: &outBuf, errBuffer: &errBuf}, nil
|
||||
}
|
136
vendor/github.com/docker/docker-ce/components/engine/integration/internal/container/ops.go
generated
vendored
Normal file
136
vendor/github.com/docker/docker-ce/components/engine/integration/internal/container/ops.go
generated
vendored
Normal file
|
@ -0,0 +1,136 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
networktypes "github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/go-connections/nat"
|
||||
)
|
||||
|
||||
// WithName sets the name of the container
|
||||
func WithName(name string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithLinks sets the links of the container
|
||||
func WithLinks(links ...string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.HostConfig.Links = links
|
||||
}
|
||||
}
|
||||
|
||||
// WithImage sets the image of the container
|
||||
func WithImage(image string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.Config.Image = image
|
||||
}
|
||||
}
|
||||
|
||||
// WithCmd sets the comannds of the container
|
||||
func WithCmd(cmds ...string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.Config.Cmd = strslice.StrSlice(cmds)
|
||||
}
|
||||
}
|
||||
|
||||
// WithNetworkMode sets the network mode of the container
|
||||
func WithNetworkMode(mode string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.HostConfig.NetworkMode = containertypes.NetworkMode(mode)
|
||||
}
|
||||
}
|
||||
|
||||
// WithExposedPorts sets the exposed ports of the container
|
||||
func WithExposedPorts(ports ...string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.Config.ExposedPorts = map[nat.Port]struct{}{}
|
||||
for _, port := range ports {
|
||||
c.Config.ExposedPorts[nat.Port(port)] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithTty sets the TTY mode of the container
|
||||
func WithTty(tty bool) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.Config.Tty = tty
|
||||
}
|
||||
}
|
||||
|
||||
// WithWorkingDir sets the working dir of the container
|
||||
func WithWorkingDir(dir string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.Config.WorkingDir = dir
|
||||
}
|
||||
}
|
||||
|
||||
// WithVolume sets the volume of the container
|
||||
func WithVolume(name string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
if c.Config.Volumes == nil {
|
||||
c.Config.Volumes = map[string]struct{}{}
|
||||
}
|
||||
c.Config.Volumes[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// WithBind sets the bind mount of the container
|
||||
func WithBind(src, target string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.HostConfig.Binds = append(c.HostConfig.Binds, fmt.Sprintf("%s:%s", src, target))
|
||||
}
|
||||
}
|
||||
|
||||
// WithIPv4 sets the specified ip for the specified network of the container
|
||||
func WithIPv4(network, ip string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
if c.NetworkingConfig.EndpointsConfig == nil {
|
||||
c.NetworkingConfig.EndpointsConfig = map[string]*networktypes.EndpointSettings{}
|
||||
}
|
||||
if v, ok := c.NetworkingConfig.EndpointsConfig[network]; !ok || v == nil {
|
||||
c.NetworkingConfig.EndpointsConfig[network] = &networktypes.EndpointSettings{}
|
||||
}
|
||||
if c.NetworkingConfig.EndpointsConfig[network].IPAMConfig == nil {
|
||||
c.NetworkingConfig.EndpointsConfig[network].IPAMConfig = &networktypes.EndpointIPAMConfig{}
|
||||
}
|
||||
c.NetworkingConfig.EndpointsConfig[network].IPAMConfig.IPv4Address = ip
|
||||
}
|
||||
}
|
||||
|
||||
// WithIPv6 sets the specified ip6 for the specified network of the container
|
||||
func WithIPv6(network, ip string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
if c.NetworkingConfig.EndpointsConfig == nil {
|
||||
c.NetworkingConfig.EndpointsConfig = map[string]*networktypes.EndpointSettings{}
|
||||
}
|
||||
if v, ok := c.NetworkingConfig.EndpointsConfig[network]; !ok || v == nil {
|
||||
c.NetworkingConfig.EndpointsConfig[network] = &networktypes.EndpointSettings{}
|
||||
}
|
||||
if c.NetworkingConfig.EndpointsConfig[network].IPAMConfig == nil {
|
||||
c.NetworkingConfig.EndpointsConfig[network].IPAMConfig = &networktypes.EndpointIPAMConfig{}
|
||||
}
|
||||
c.NetworkingConfig.EndpointsConfig[network].IPAMConfig.IPv6Address = ip
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogDriver sets the log driver to use for the container
|
||||
func WithLogDriver(driver string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
if c.HostConfig == nil {
|
||||
c.HostConfig = &containertypes.HostConfig{}
|
||||
}
|
||||
c.HostConfig.LogConfig.Type = driver
|
||||
}
|
||||
}
|
||||
|
||||
// WithAutoRemove sets the container to be removed on exit
|
||||
func WithAutoRemove(c *TestContainerConfig) {
|
||||
if c.HostConfig == nil {
|
||||
c.HostConfig = &containertypes.HostConfig{}
|
||||
}
|
||||
c.HostConfig.AutoRemove = true
|
||||
}
|
41
vendor/github.com/docker/docker-ce/components/engine/integration/internal/container/states.go
generated
vendored
Normal file
41
vendor/github.com/docker/docker-ce/components/engine/integration/internal/container/states.go
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"gotest.tools/poll"
|
||||
)
|
||||
|
||||
// IsStopped verifies the container is in stopped state.
|
||||
func IsStopped(ctx context.Context, client client.APIClient, containerID string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
inspect, err := client.ContainerInspect(ctx, containerID)
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
return poll.Error(err)
|
||||
case !inspect.State.Running:
|
||||
return poll.Success()
|
||||
default:
|
||||
return poll.Continue("waiting for container to be stopped")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsInState verifies the container is in one of the specified state, e.g., "running", "exited", etc.
|
||||
func IsInState(ctx context.Context, client client.APIClient, containerID string, state ...string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
inspect, err := client.ContainerInspect(ctx, containerID)
|
||||
if err != nil {
|
||||
return poll.Error(err)
|
||||
}
|
||||
for _, v := range state {
|
||||
if inspect.State.Status == v {
|
||||
return poll.Success()
|
||||
}
|
||||
}
|
||||
return poll.Continue("waiting for container to be one of (%s), currently %s", strings.Join(state, ", "), inspect.State.Status)
|
||||
}
|
||||
}
|
36
vendor/github.com/docker/docker-ce/components/engine/integration/internal/network/network.go
generated
vendored
Normal file
36
vendor/github.com/docker/docker-ce/components/engine/integration/internal/network/network.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func createNetwork(ctx context.Context, client client.APIClient, name string, ops ...func(*types.NetworkCreate)) (string, error) {
|
||||
config := types.NetworkCreate{}
|
||||
|
||||
for _, op := range ops {
|
||||
op(&config)
|
||||
}
|
||||
|
||||
n, err := client.NetworkCreate(ctx, name, config)
|
||||
return n.ID, err
|
||||
}
|
||||
|
||||
// Create creates a network with the specified options
|
||||
func Create(ctx context.Context, client client.APIClient, name string, ops ...func(*types.NetworkCreate)) (string, error) {
|
||||
return createNetwork(ctx, client, name, ops...)
|
||||
}
|
||||
|
||||
// CreateNoError creates a network with the specified options and verifies there were no errors
|
||||
// nolint: golint
|
||||
func CreateNoError(t *testing.T, ctx context.Context, client client.APIClient, name string, ops ...func(*types.NetworkCreate)) string { // nolint: golint
|
||||
t.Helper()
|
||||
|
||||
name, err := createNetwork(ctx, client, name, ops...)
|
||||
assert.NilError(t, err)
|
||||
return name
|
||||
}
|
94
vendor/github.com/docker/docker-ce/components/engine/integration/internal/network/ops.go
generated
vendored
Normal file
94
vendor/github.com/docker/docker-ce/components/engine/integration/internal/network/ops.go
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
)
|
||||
|
||||
// WithDriver sets the driver of the network
|
||||
func WithDriver(driver string) func(*types.NetworkCreate) {
|
||||
return func(n *types.NetworkCreate) {
|
||||
n.Driver = driver
|
||||
}
|
||||
}
|
||||
|
||||
// WithIPv6 Enables IPv6 on the network
|
||||
func WithIPv6() func(*types.NetworkCreate) {
|
||||
return func(n *types.NetworkCreate) {
|
||||
n.EnableIPv6 = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithCheckDuplicate sets the CheckDuplicate field on create network request
|
||||
func WithCheckDuplicate() func(*types.NetworkCreate) {
|
||||
return func(n *types.NetworkCreate) {
|
||||
n.CheckDuplicate = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithInternal enables Internal flag on the create network request
|
||||
func WithInternal() func(*types.NetworkCreate) {
|
||||
return func(n *types.NetworkCreate) {
|
||||
n.Internal = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithAttachable sets Attachable flag on the create network request
|
||||
func WithAttachable() func(*types.NetworkCreate) {
|
||||
return func(n *types.NetworkCreate) {
|
||||
n.Attachable = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithMacvlan sets the network as macvlan with the specified parent
|
||||
func WithMacvlan(parent string) func(*types.NetworkCreate) {
|
||||
return func(n *types.NetworkCreate) {
|
||||
n.Driver = "macvlan"
|
||||
if parent != "" {
|
||||
n.Options = map[string]string{
|
||||
"parent": parent,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithIPvlan sets the network as ipvlan with the specified parent and mode
|
||||
func WithIPvlan(parent, mode string) func(*types.NetworkCreate) {
|
||||
return func(n *types.NetworkCreate) {
|
||||
n.Driver = "ipvlan"
|
||||
if n.Options == nil {
|
||||
n.Options = map[string]string{}
|
||||
}
|
||||
if parent != "" {
|
||||
n.Options["parent"] = parent
|
||||
}
|
||||
if mode != "" {
|
||||
n.Options["ipvlan_mode"] = mode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithOption adds the specified key/value pair to network's options
|
||||
func WithOption(key, value string) func(*types.NetworkCreate) {
|
||||
return func(n *types.NetworkCreate) {
|
||||
if n.Options == nil {
|
||||
n.Options = map[string]string{}
|
||||
}
|
||||
n.Options[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// WithIPAM adds an IPAM with the specified Subnet and Gateway to the network
|
||||
func WithIPAM(subnet, gateway string) func(*types.NetworkCreate) {
|
||||
return func(n *types.NetworkCreate) {
|
||||
if n.IPAM == nil {
|
||||
n.IPAM = &network.IPAM{}
|
||||
}
|
||||
|
||||
n.IPAM.Config = append(n.IPAM.Config, network.IPAMConfig{
|
||||
Subnet: subnet,
|
||||
Gateway: gateway,
|
||||
AuxAddress: map[string]string{},
|
||||
})
|
||||
}
|
||||
}
|
53
vendor/github.com/docker/docker-ce/components/engine/integration/internal/requirement/requirement.go
generated
vendored
Normal file
53
vendor/github.com/docker/docker-ce/components/engine/integration/internal/requirement/requirement.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
package requirement // import "github.com/docker/docker/integration/internal/requirement"
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// HasHubConnectivity checks to see if https://hub.docker.com is
|
||||
// accessible from the present environment
|
||||
func HasHubConnectivity(t *testing.T) bool {
|
||||
t.Helper()
|
||||
// Set a timeout on the GET at 15s
|
||||
var timeout = 15 * time.Second
|
||||
var url = "https://hub.docker.com"
|
||||
|
||||
client := http.Client{Timeout: timeout}
|
||||
resp, err := client.Get(url)
|
||||
if err != nil && strings.Contains(err.Error(), "use of closed network connection") {
|
||||
t.Fatalf("Timeout for GET request on %s", url)
|
||||
}
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func overlayFSSupported() bool {
|
||||
result := icmd.RunCommand("/bin/sh", "-c", "cat /proc/filesystems")
|
||||
if result.Error != nil {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(result.Combined(), "overlay\n")
|
||||
}
|
||||
|
||||
// Overlay2Supported returns true if the current system supports overlay2 as graphdriver
|
||||
func Overlay2Supported(kernelVersion string) bool {
|
||||
if !overlayFSSupported() {
|
||||
return false
|
||||
}
|
||||
|
||||
daemonV, err := kernel.ParseRelease(kernelVersion)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
requiredV := kernel.VersionInfo{Kernel: 4}
|
||||
return kernel.CompareKernelVersion(*daemonV, requiredV) > -1
|
||||
|
||||
}
|
200
vendor/github.com/docker/docker-ce/components/engine/integration/internal/swarm/service.go
generated
vendored
Normal file
200
vendor/github.com/docker/docker-ce/components/engine/integration/internal/swarm/service.go
generated
vendored
Normal file
|
@ -0,0 +1,200 @@
|
|||
package swarm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
// ServicePoll tweaks the pollSettings for `service`
|
||||
func ServicePoll(config *poll.Settings) {
|
||||
// Override the default pollSettings for `service` resource here ...
|
||||
config.Timeout = 30 * time.Second
|
||||
config.Delay = 100 * time.Millisecond
|
||||
if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
|
||||
config.Timeout = 90 * time.Second
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkPoll tweaks the pollSettings for `network`
|
||||
func NetworkPoll(config *poll.Settings) {
|
||||
// Override the default pollSettings for `network` resource here ...
|
||||
config.Timeout = 30 * time.Second
|
||||
config.Delay = 100 * time.Millisecond
|
||||
|
||||
if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
|
||||
config.Timeout = 50 * time.Second
|
||||
}
|
||||
}
|
||||
|
||||
// ContainerPoll tweaks the pollSettings for `container`
|
||||
func ContainerPoll(config *poll.Settings) {
|
||||
// Override the default pollSettings for `container` resource here ...
|
||||
|
||||
if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
|
||||
config.Timeout = 30 * time.Second
|
||||
config.Delay = 100 * time.Millisecond
|
||||
}
|
||||
}
|
||||
|
||||
// NewSwarm creates a swarm daemon for testing
|
||||
func NewSwarm(t *testing.T, testEnv *environment.Execution, ops ...func(*daemon.Daemon)) *daemon.Daemon {
|
||||
t.Helper()
|
||||
skip.If(t, testEnv.IsRemoteDaemon)
|
||||
if testEnv.DaemonInfo.ExperimentalBuild {
|
||||
ops = append(ops, daemon.WithExperimental)
|
||||
}
|
||||
d := daemon.New(t, ops...)
|
||||
d.StartAndSwarmInit(t)
|
||||
return d
|
||||
}
|
||||
|
||||
// ServiceSpecOpt is used with `CreateService` to pass in service spec modifiers
|
||||
type ServiceSpecOpt func(*swarmtypes.ServiceSpec)
|
||||
|
||||
// CreateService creates a service on the passed in swarm daemon.
|
||||
func CreateService(t *testing.T, d *daemon.Daemon, opts ...ServiceSpecOpt) string {
|
||||
t.Helper()
|
||||
spec := defaultServiceSpec()
|
||||
for _, o := range opts {
|
||||
o(&spec)
|
||||
}
|
||||
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
resp, err := client.ServiceCreate(context.Background(), spec, types.ServiceCreateOptions{})
|
||||
assert.NilError(t, err, "error creating service")
|
||||
return resp.ID
|
||||
}
|
||||
|
||||
func defaultServiceSpec() swarmtypes.ServiceSpec {
|
||||
var spec swarmtypes.ServiceSpec
|
||||
ServiceWithImage("busybox:latest")(&spec)
|
||||
ServiceWithCommand([]string{"/bin/top"})(&spec)
|
||||
ServiceWithReplicas(1)(&spec)
|
||||
return spec
|
||||
}
|
||||
|
||||
// ServiceWithInit sets whether the service should use init or not
|
||||
func ServiceWithInit(b *bool) func(*swarmtypes.ServiceSpec) {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
ensureContainerSpec(spec)
|
||||
spec.TaskTemplate.ContainerSpec.Init = b
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceWithImage sets the image to use for the service
|
||||
func ServiceWithImage(image string) func(*swarmtypes.ServiceSpec) {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
ensureContainerSpec(spec)
|
||||
spec.TaskTemplate.ContainerSpec.Image = image
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceWithCommand sets the command to use for the service
|
||||
func ServiceWithCommand(cmd []string) ServiceSpecOpt {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
ensureContainerSpec(spec)
|
||||
spec.TaskTemplate.ContainerSpec.Command = cmd
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceWithConfig adds the config reference to the service
|
||||
func ServiceWithConfig(configRef *swarmtypes.ConfigReference) ServiceSpecOpt {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
ensureContainerSpec(spec)
|
||||
spec.TaskTemplate.ContainerSpec.Configs = append(spec.TaskTemplate.ContainerSpec.Configs, configRef)
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceWithSecret adds the secret reference to the service
|
||||
func ServiceWithSecret(secretRef *swarmtypes.SecretReference) ServiceSpecOpt {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
ensureContainerSpec(spec)
|
||||
spec.TaskTemplate.ContainerSpec.Secrets = append(spec.TaskTemplate.ContainerSpec.Secrets, secretRef)
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceWithReplicas sets the replicas for the service
|
||||
func ServiceWithReplicas(n uint64) ServiceSpecOpt {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
spec.Mode = swarmtypes.ServiceMode{
|
||||
Replicated: &swarmtypes.ReplicatedService{
|
||||
Replicas: &n,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceWithName sets the name of the service
|
||||
func ServiceWithName(name string) ServiceSpecOpt {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
spec.Annotations.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceWithNetwork sets the network of the service
|
||||
func ServiceWithNetwork(network string) ServiceSpecOpt {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
spec.TaskTemplate.Networks = append(spec.TaskTemplate.Networks,
|
||||
swarmtypes.NetworkAttachmentConfig{Target: network})
|
||||
}
|
||||
}
|
||||
|
||||
// ServiceWithEndpoint sets the Endpoint of the service
|
||||
func ServiceWithEndpoint(endpoint *swarmtypes.EndpointSpec) ServiceSpecOpt {
|
||||
return func(spec *swarmtypes.ServiceSpec) {
|
||||
spec.EndpointSpec = endpoint
|
||||
}
|
||||
}
|
||||
|
||||
// GetRunningTasks gets the list of running tasks for a service
|
||||
func GetRunningTasks(t *testing.T, d *daemon.Daemon, serviceID string) []swarmtypes.Task {
|
||||
t.Helper()
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
filterArgs := filters.NewArgs()
|
||||
filterArgs.Add("desired-state", "running")
|
||||
filterArgs.Add("service", serviceID)
|
||||
|
||||
options := types.TaskListOptions{
|
||||
Filters: filterArgs,
|
||||
}
|
||||
tasks, err := client.TaskList(context.Background(), options)
|
||||
assert.NilError(t, err)
|
||||
return tasks
|
||||
}
|
||||
|
||||
// ExecTask runs the passed in exec config on the given task
|
||||
func ExecTask(t *testing.T, d *daemon.Daemon, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
|
||||
t.Helper()
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
resp, err := client.ContainerExecCreate(ctx, task.Status.ContainerStatus.ContainerID, config)
|
||||
assert.NilError(t, err, "error creating exec")
|
||||
|
||||
startCheck := types.ExecStartCheck{}
|
||||
attach, err := client.ContainerExecAttach(ctx, resp.ID, startCheck)
|
||||
assert.NilError(t, err, "error attaching to exec")
|
||||
return attach
|
||||
}
|
||||
|
||||
func ensureContainerSpec(spec *swarmtypes.ServiceSpec) {
|
||||
if spec.TaskTemplate.ContainerSpec == nil {
|
||||
spec.TaskTemplate.ContainerSpec = &swarmtypes.ContainerSpec{}
|
||||
}
|
||||
}
|
91
vendor/github.com/docker/docker-ce/components/engine/integration/network/delete_test.go
generated
vendored
Normal file
91
vendor/github.com/docker/docker-ce/components/engine/integration/network/delete_test.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
package network // import "github.com/docker/docker/integration/network"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration/internal/network"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func containsNetwork(nws []types.NetworkResource, networkID string) bool {
|
||||
for _, n := range nws {
|
||||
if n.ID == networkID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// createAmbiguousNetworks creates three networks, of which the second network
|
||||
// uses a prefix of the first network's ID as name. The third network uses the
|
||||
// first network's ID as name.
|
||||
//
|
||||
// After successful creation, properties of all three networks is returned
|
||||
func createAmbiguousNetworks(t *testing.T) (string, string, string) {
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
testNet := network.CreateNoError(t, ctx, client, "testNet")
|
||||
idPrefixNet := network.CreateNoError(t, ctx, client, testNet[:12])
|
||||
fullIDNet := network.CreateNoError(t, ctx, client, testNet)
|
||||
|
||||
nws, err := client.NetworkList(ctx, types.NetworkListOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, is.Equal(true, containsNetwork(nws, testNet)), "failed to create network testNet")
|
||||
assert.Check(t, is.Equal(true, containsNetwork(nws, idPrefixNet)), "failed to create network idPrefixNet")
|
||||
assert.Check(t, is.Equal(true, containsNetwork(nws, fullIDNet)), "failed to create network fullIDNet")
|
||||
return testNet, idPrefixNet, fullIDNet
|
||||
}
|
||||
|
||||
func TestNetworkCreateDelete(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
netName := "testnetwork_" + t.Name()
|
||||
network.CreateNoError(t, ctx, client, netName,
|
||||
network.WithCheckDuplicate(),
|
||||
)
|
||||
assert.Check(t, IsNetworkAvailable(client, netName))
|
||||
|
||||
// delete the network and make sure it is deleted
|
||||
err := client.NetworkRemove(ctx, netName)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, IsNetworkNotAvailable(client, netName))
|
||||
}
|
||||
|
||||
// TestDockerNetworkDeletePreferID tests that if a network with a name
|
||||
// equal to another network's ID exists, the Network with the given
|
||||
// ID is removed, and not the network with the given name.
|
||||
func TestDockerNetworkDeletePreferID(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.34"), "broken in earlier versions")
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
testNet, idPrefixNet, fullIDNet := createAmbiguousNetworks(t)
|
||||
|
||||
// Delete the network using a prefix of the first network's ID as name.
|
||||
// This should the network name with the id-prefix, not the original network.
|
||||
err := client.NetworkRemove(ctx, testNet[:12])
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Delete the network using networkID. This should remove the original
|
||||
// network, not the network with the name equal to the networkID
|
||||
err = client.NetworkRemove(ctx, testNet)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// networks "testNet" and "idPrefixNet" should be removed, but "fullIDNet" should still exist
|
||||
nws, err := client.NetworkList(ctx, types.NetworkListOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(false, containsNetwork(nws, testNet)), "Network testNet not removed")
|
||||
assert.Check(t, is.Equal(false, containsNetwork(nws, idPrefixNet)), "Network idPrefixNet not removed")
|
||||
assert.Check(t, is.Equal(true, containsNetwork(nws, fullIDNet)), "Network fullIDNet not found")
|
||||
}
|
92
vendor/github.com/docker/docker-ce/components/engine/integration/network/helpers.go
generated
vendored
Normal file
92
vendor/github.com/docker/docker-ce/components/engine/integration/network/helpers.go
generated
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"gotest.tools/assert/cmp"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// CreateMasterDummy creates a dummy network interface
|
||||
func CreateMasterDummy(t *testing.T, master string) {
|
||||
// ip link add <dummy_name> type dummy
|
||||
icmd.RunCommand("ip", "link", "add", master, "type", "dummy").Assert(t, icmd.Success)
|
||||
icmd.RunCommand("ip", "link", "set", master, "up").Assert(t, icmd.Success)
|
||||
}
|
||||
|
||||
// CreateVlanInterface creates a vlan network interface
|
||||
func CreateVlanInterface(t *testing.T, master, slave, id string) {
|
||||
// ip link add link <master> name <master>.<VID> type vlan id <VID>
|
||||
icmd.RunCommand("ip", "link", "add", "link", master, "name", slave, "type", "vlan", "id", id).Assert(t, icmd.Success)
|
||||
// ip link set <sub_interface_name> up
|
||||
icmd.RunCommand("ip", "link", "set", slave, "up").Assert(t, icmd.Success)
|
||||
}
|
||||
|
||||
// DeleteInterface deletes a network interface
|
||||
func DeleteInterface(t *testing.T, ifName string) {
|
||||
icmd.RunCommand("ip", "link", "delete", ifName).Assert(t, icmd.Success)
|
||||
icmd.RunCommand("iptables", "-t", "nat", "--flush").Assert(t, icmd.Success)
|
||||
icmd.RunCommand("iptables", "--flush").Assert(t, icmd.Success)
|
||||
}
|
||||
|
||||
// LinkExists verifies that a link exists
|
||||
func LinkExists(t *testing.T, master string) {
|
||||
// verify the specified link exists, ip link show <link_name>
|
||||
icmd.RunCommand("ip", "link", "show", master).Assert(t, icmd.Success)
|
||||
}
|
||||
|
||||
// IsNetworkAvailable provides a comparison to check if a docker network is available
|
||||
func IsNetworkAvailable(c client.NetworkAPIClient, name string) cmp.Comparison {
|
||||
return func() cmp.Result {
|
||||
networks, err := c.NetworkList(context.Background(), types.NetworkListOptions{})
|
||||
if err != nil {
|
||||
return cmp.ResultFromError(err)
|
||||
}
|
||||
for _, network := range networks {
|
||||
if network.Name == name {
|
||||
return cmp.ResultSuccess
|
||||
}
|
||||
}
|
||||
return cmp.ResultFailure(fmt.Sprintf("could not find network %s", name))
|
||||
}
|
||||
}
|
||||
|
||||
// IsNetworkNotAvailable provides a comparison to check if a docker network is not available
|
||||
func IsNetworkNotAvailable(c client.NetworkAPIClient, name string) cmp.Comparison {
|
||||
return func() cmp.Result {
|
||||
networks, err := c.NetworkList(context.Background(), types.NetworkListOptions{})
|
||||
if err != nil {
|
||||
return cmp.ResultFromError(err)
|
||||
}
|
||||
for _, network := range networks {
|
||||
if network.Name == name {
|
||||
return cmp.ResultFailure(fmt.Sprintf("network %s is still present", name))
|
||||
}
|
||||
}
|
||||
return cmp.ResultSuccess
|
||||
}
|
||||
}
|
||||
|
||||
// CheckKernelMajorVersionGreaterOrEqualThen returns whether the kernel version is greater or equal than the one provided
|
||||
func CheckKernelMajorVersionGreaterOrEqualThen(kernelVersion int, majorVersion int) bool {
|
||||
kv, err := kernel.GetKernelVersion()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if kv.Kernel < kernelVersion || (kv.Kernel == kernelVersion && kv.Major < majorVersion) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsUserNamespace returns whether the user namespace remapping is enabled
|
||||
func IsUserNamespace() bool {
|
||||
root := os.Getenv("DOCKER_REMAP_ROOT")
|
||||
return root != ""
|
||||
}
|
177
vendor/github.com/docker/docker-ce/components/engine/integration/network/inspect_test.go
generated
vendored
Normal file
177
vendor/github.com/docker/docker-ce/components/engine/integration/network/inspect_test.go
generated
vendored
Normal file
|
@ -0,0 +1,177 @@
|
|||
package network // import "github.com/docker/docker/integration/network"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/network"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/poll"
|
||||
)
|
||||
|
||||
const defaultSwarmPort = 2477
|
||||
|
||||
func TestInspectNetwork(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
overlayName := "overlay1"
|
||||
overlayID := network.CreateNoError(t, context.Background(), client, overlayName,
|
||||
network.WithDriver("overlay"),
|
||||
network.WithCheckDuplicate(),
|
||||
)
|
||||
|
||||
var instances uint64 = 4
|
||||
serviceName := "TestService" + t.Name()
|
||||
|
||||
serviceID := swarm.CreateService(t, d,
|
||||
swarm.ServiceWithReplicas(instances),
|
||||
swarm.ServiceWithName(serviceName),
|
||||
swarm.ServiceWithNetwork(overlayName),
|
||||
)
|
||||
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, instances), swarm.ServicePoll)
|
||||
|
||||
_, _, err := client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Test inspect verbose with full NetworkID
|
||||
networkVerbose, err := client.NetworkInspect(context.Background(), overlayID, types.NetworkInspectOptions{
|
||||
Verbose: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, validNetworkVerbose(networkVerbose, serviceName, instances))
|
||||
|
||||
// Test inspect verbose with partial NetworkID
|
||||
networkVerbose, err = client.NetworkInspect(context.Background(), overlayID[0:11], types.NetworkInspectOptions{
|
||||
Verbose: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, validNetworkVerbose(networkVerbose, serviceName, instances))
|
||||
|
||||
// Test inspect verbose with Network name and swarm scope
|
||||
networkVerbose, err = client.NetworkInspect(context.Background(), overlayName, types.NetworkInspectOptions{
|
||||
Verbose: true,
|
||||
Scope: "swarm",
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, validNetworkVerbose(networkVerbose, serviceName, instances))
|
||||
|
||||
err = client.ServiceRemove(context.Background(), serviceID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, serviceIsRemoved(client, serviceID), swarm.ServicePoll)
|
||||
poll.WaitOn(t, noTasks(client), swarm.ServicePoll)
|
||||
|
||||
serviceID2 := swarm.CreateService(t, d,
|
||||
swarm.ServiceWithReplicas(instances),
|
||||
swarm.ServiceWithName(serviceName),
|
||||
swarm.ServiceWithNetwork(overlayName),
|
||||
)
|
||||
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID2, instances), swarm.ServicePoll)
|
||||
|
||||
err = client.ServiceRemove(context.Background(), serviceID2)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, serviceIsRemoved(client, serviceID2), swarm.ServicePoll)
|
||||
poll.WaitOn(t, noTasks(client), swarm.ServicePoll)
|
||||
|
||||
err = client.NetworkRemove(context.Background(), overlayID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, networkIsRemoved(client, overlayID), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
|
||||
}
|
||||
|
||||
func serviceRunningTasksCount(client client.ServiceAPIClient, serviceID string, instances uint64) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("service", serviceID)
|
||||
tasks, err := client.TaskList(context.Background(), types.TaskListOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
switch {
|
||||
case err != nil:
|
||||
return poll.Error(err)
|
||||
case len(tasks) == int(instances):
|
||||
for _, task := range tasks {
|
||||
if task.Status.State != swarmtypes.TaskStateRunning {
|
||||
return poll.Continue("waiting for tasks to enter run state")
|
||||
}
|
||||
}
|
||||
return poll.Success()
|
||||
default:
|
||||
return poll.Continue("task count at %d waiting for %d", len(tasks), instances)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func networkIsRemoved(client client.NetworkAPIClient, networkID string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
_, err := client.NetworkInspect(context.Background(), networkID, types.NetworkInspectOptions{})
|
||||
if err == nil {
|
||||
return poll.Continue("waiting for network %s to be removed", networkID)
|
||||
}
|
||||
return poll.Success()
|
||||
}
|
||||
}
|
||||
|
||||
func serviceIsRemoved(client client.ServiceAPIClient, serviceID string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("service", serviceID)
|
||||
_, err := client.TaskList(context.Background(), types.TaskListOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
if err == nil {
|
||||
return poll.Continue("waiting for service %s to be deleted", serviceID)
|
||||
}
|
||||
return poll.Success()
|
||||
}
|
||||
}
|
||||
|
||||
func noTasks(client client.ServiceAPIClient) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
filter := filters.NewArgs()
|
||||
tasks, err := client.TaskList(context.Background(), types.TaskListOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
switch {
|
||||
case err != nil:
|
||||
return poll.Error(err)
|
||||
case len(tasks) == 0:
|
||||
return poll.Success()
|
||||
default:
|
||||
return poll.Continue("task count at %d waiting for 0", len(tasks))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if Service and Tasks info are part of the inspect verbose response
|
||||
func validNetworkVerbose(network types.NetworkResource, service string, instances uint64) bool {
|
||||
if service, ok := network.Services[service]; ok {
|
||||
if len(service.Tasks) != int(instances) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if network.IPAM.Config == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, cfg := range network.IPAM.Config {
|
||||
if cfg.Gateway == "" || cfg.Subnet == "" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
432
vendor/github.com/docker/docker-ce/components/engine/integration/network/ipvlan/ipvlan_test.go
generated
vendored
Normal file
432
vendor/github.com/docker/docker-ce/components/engine/integration/network/ipvlan/ipvlan_test.go
generated
vendored
Normal file
|
@ -0,0 +1,432 @@
|
|||
package ipvlan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
dclient "github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
net "github.com/docker/docker/integration/internal/network"
|
||||
n "github.com/docker/docker/integration/network"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestDockerNetworkIpvlanPersistance(t *testing.T) {
|
||||
// verify the driver automatically provisions the 802.1q link (di-dummy0.70)
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
skip.If(t, !ipvlanKernelSupport(), "Kernel doesn't support ipvlan")
|
||||
|
||||
d := daemon.New(t, daemon.WithExperimental)
|
||||
d.StartWithBusybox(t)
|
||||
defer d.Stop(t)
|
||||
|
||||
// master dummy interface 'di' notation represent 'docker ipvlan'
|
||||
master := "di-dummy0"
|
||||
n.CreateMasterDummy(t, master)
|
||||
defer n.DeleteInterface(t, master)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
// create a network specifying the desired sub-interface name
|
||||
netName := "di-persist"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithIPvlan("di-dummy0.70", ""),
|
||||
)
|
||||
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
// Restart docker daemon to test the config has persisted to disk
|
||||
d.Restart(t)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
}
|
||||
|
||||
func TestDockerNetworkIpvlan(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
skip.If(t, !ipvlanKernelSupport(), "Kernel doesn't support ipvlan")
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
test func(dclient.APIClient) func(*testing.T)
|
||||
}{
|
||||
{
|
||||
name: "Subinterface",
|
||||
test: testIpvlanSubinterface,
|
||||
}, {
|
||||
name: "OverlapParent",
|
||||
test: testIpvlanOverlapParent,
|
||||
}, {
|
||||
name: "L2NilParent",
|
||||
test: testIpvlanL2NilParent,
|
||||
}, {
|
||||
name: "L2InternalMode",
|
||||
test: testIpvlanL2InternalMode,
|
||||
}, {
|
||||
name: "L3NilParent",
|
||||
test: testIpvlanL3NilParent,
|
||||
}, {
|
||||
name: "L3InternalMode",
|
||||
test: testIpvlanL3InternalMode,
|
||||
}, {
|
||||
name: "L2MultiSubnet",
|
||||
test: testIpvlanL2MultiSubnet,
|
||||
}, {
|
||||
name: "L3MultiSubnet",
|
||||
test: testIpvlanL3MultiSubnet,
|
||||
}, {
|
||||
name: "Addressing",
|
||||
test: testIpvlanAddressing,
|
||||
},
|
||||
} {
|
||||
d := daemon.New(t, daemon.WithExperimental)
|
||||
d.StartWithBusybox(t)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
t.Run(tc.name, tc.test(client))
|
||||
|
||||
d.Stop(t)
|
||||
// FIXME(vdemeester) clean network
|
||||
}
|
||||
}
|
||||
|
||||
func testIpvlanSubinterface(client dclient.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
master := "di-dummy0"
|
||||
n.CreateMasterDummy(t, master)
|
||||
defer n.DeleteInterface(t, master)
|
||||
|
||||
netName := "di-subinterface"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithIPvlan("di-dummy0.60", ""),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
// delete the network while preserving the parent link
|
||||
err := client.NetworkRemove(context.Background(), netName)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, n.IsNetworkNotAvailable(client, netName))
|
||||
// verify the network delete did not delete the predefined link
|
||||
n.LinkExists(t, "di-dummy0")
|
||||
}
|
||||
}
|
||||
|
||||
func testIpvlanOverlapParent(client dclient.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
// verify the same parent interface cannot be used if already in use by an existing network
|
||||
master := "di-dummy0"
|
||||
parent := master + ".30"
|
||||
n.CreateMasterDummy(t, master)
|
||||
defer n.DeleteInterface(t, master)
|
||||
n.CreateVlanInterface(t, master, parent, "30")
|
||||
|
||||
netName := "di-subinterface"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithIPvlan(parent, ""),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
_, err := net.Create(context.Background(), client, netName,
|
||||
net.WithIPvlan(parent, ""),
|
||||
)
|
||||
// verify that the overlap returns an error
|
||||
assert.Check(t, err != nil)
|
||||
}
|
||||
}
|
||||
|
||||
func testIpvlanL2NilParent(client dclient.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
// ipvlan l2 mode - dummy parent interface is provisioned dynamically
|
||||
netName := "di-nil-parent"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithIPvlan("", ""),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
|
||||
id2 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
|
||||
|
||||
_, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func testIpvlanL2InternalMode(client dclient.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
netName := "di-internal"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithIPvlan("", ""),
|
||||
net.WithInternal(),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
|
||||
id2 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
|
||||
|
||||
timeoutCtx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
_, err := container.Exec(timeoutCtx, client, id1, []string{"ping", "-c", "1", "-w", "1", "8.8.8.8"})
|
||||
// FIXME(vdemeester) check the time of error ?
|
||||
assert.Check(t, err != nil)
|
||||
assert.Check(t, timeoutCtx.Err() == context.DeadlineExceeded)
|
||||
|
||||
_, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func testIpvlanL3NilParent(client dclient.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
netName := "di-nil-parent-l3"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithIPvlan("", "l3"),
|
||||
net.WithIPAM("172.28.230.0/24", ""),
|
||||
net.WithIPAM("172.28.220.0/24", ""),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.220.10"),
|
||||
)
|
||||
id2 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.230.10"),
|
||||
)
|
||||
|
||||
_, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func testIpvlanL3InternalMode(client dclient.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
netName := "di-internal-l3"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithIPvlan("", "l3"),
|
||||
net.WithInternal(),
|
||||
net.WithIPAM("172.28.230.0/24", ""),
|
||||
net.WithIPAM("172.28.220.0/24", ""),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.220.10"),
|
||||
)
|
||||
id2 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.230.10"),
|
||||
)
|
||||
|
||||
timeoutCtx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
_, err := container.Exec(timeoutCtx, client, id1, []string{"ping", "-c", "1", "-w", "1", "8.8.8.8"})
|
||||
// FIXME(vdemeester) check the time of error ?
|
||||
assert.Check(t, err != nil)
|
||||
assert.Check(t, timeoutCtx.Err() == context.DeadlineExceeded)
|
||||
|
||||
_, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func testIpvlanL2MultiSubnet(client dclient.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
netName := "dualstackl2"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithIPvlan("", ""),
|
||||
net.WithIPv6(),
|
||||
net.WithIPAM("172.28.200.0/24", ""),
|
||||
net.WithIPAM("172.28.202.0/24", "172.28.202.254"),
|
||||
net.WithIPAM("2001:db8:abc8::/64", ""),
|
||||
net.WithIPAM("2001:db8:abc6::/64", "2001:db8:abc6::254"),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.100.0/24 and 2001:db8:abc2::/64
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.200.20"),
|
||||
container.WithIPv6(netName, "2001:db8:abc8::20"),
|
||||
)
|
||||
id2 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.200.21"),
|
||||
container.WithIPv6(netName, "2001:db8:abc8::21"),
|
||||
)
|
||||
c1, err := client.ContainerInspect(ctx, id1)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// verify ipv4 connectivity to the explicit --ipv address second to first
|
||||
_, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", c1.NetworkSettings.Networks[netName].IPAddress})
|
||||
assert.NilError(t, err)
|
||||
// verify ipv6 connectivity to the explicit --ipv6 address second to first
|
||||
_, err = container.Exec(ctx, client, id2, []string{"ping6", "-c", "1", c1.NetworkSettings.Networks[netName].GlobalIPv6Address})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.102.0/24 and 2001:db8:abc4::/64
|
||||
id3 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.202.20"),
|
||||
container.WithIPv6(netName, "2001:db8:abc6::20"),
|
||||
)
|
||||
id4 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.202.21"),
|
||||
container.WithIPv6(netName, "2001:db8:abc6::21"),
|
||||
)
|
||||
c3, err := client.ContainerInspect(ctx, id3)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// verify ipv4 connectivity to the explicit --ipv address from third to fourth
|
||||
_, err = container.Exec(ctx, client, id4, []string{"ping", "-c", "1", c3.NetworkSettings.Networks[netName].IPAddress})
|
||||
assert.NilError(t, err)
|
||||
// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
|
||||
_, err = container.Exec(ctx, client, id4, []string{"ping6", "-c", "1", c3.NetworkSettings.Networks[netName].GlobalIPv6Address})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Inspect the v4 gateway to ensure the proper default GW was assigned
|
||||
assert.Equal(t, c1.NetworkSettings.Networks[netName].Gateway, "172.28.200.1")
|
||||
// Inspect the v6 gateway to ensure the proper default GW was assigned
|
||||
assert.Equal(t, c1.NetworkSettings.Networks[netName].IPv6Gateway, "2001:db8:abc8::1")
|
||||
// Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned
|
||||
assert.Equal(t, c3.NetworkSettings.Networks[netName].Gateway, "172.28.202.254")
|
||||
// Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned
|
||||
assert.Equal(t, c3.NetworkSettings.Networks[netName].IPv6Gateway, "2001:db8:abc6::254")
|
||||
}
|
||||
}
|
||||
|
||||
func testIpvlanL3MultiSubnet(client dclient.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
netName := "dualstackl3"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithIPvlan("", "l3"),
|
||||
net.WithIPv6(),
|
||||
net.WithIPAM("172.28.10.0/24", ""),
|
||||
net.WithIPAM("172.28.12.0/24", "172.28.12.254"),
|
||||
net.WithIPAM("2001:db8:abc9::/64", ""),
|
||||
net.WithIPAM("2001:db8:abc7::/64", "2001:db8:abc7::254"),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.100.0/24 and 2001:db8:abc2::/64
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.10.20"),
|
||||
container.WithIPv6(netName, "2001:db8:abc9::20"),
|
||||
)
|
||||
id2 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.10.21"),
|
||||
container.WithIPv6(netName, "2001:db8:abc9::21"),
|
||||
)
|
||||
c1, err := client.ContainerInspect(ctx, id1)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// verify ipv4 connectivity to the explicit --ipv address second to first
|
||||
_, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", c1.NetworkSettings.Networks[netName].IPAddress})
|
||||
assert.NilError(t, err)
|
||||
// verify ipv6 connectivity to the explicit --ipv6 address second to first
|
||||
_, err = container.Exec(ctx, client, id2, []string{"ping6", "-c", "1", c1.NetworkSettings.Networks[netName].GlobalIPv6Address})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.102.0/24 and 2001:db8:abc4::/64
|
||||
id3 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.12.20"),
|
||||
container.WithIPv6(netName, "2001:db8:abc7::20"),
|
||||
)
|
||||
id4 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netName),
|
||||
container.WithIPv4(netName, "172.28.12.21"),
|
||||
container.WithIPv6(netName, "2001:db8:abc7::21"),
|
||||
)
|
||||
c3, err := client.ContainerInspect(ctx, id3)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// verify ipv4 connectivity to the explicit --ipv address from third to fourth
|
||||
_, err = container.Exec(ctx, client, id4, []string{"ping", "-c", "1", c3.NetworkSettings.Networks[netName].IPAddress})
|
||||
assert.NilError(t, err)
|
||||
// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
|
||||
_, err = container.Exec(ctx, client, id4, []string{"ping6", "-c", "1", c3.NetworkSettings.Networks[netName].GlobalIPv6Address})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Inspect the v4 gateway to ensure no next hop is assigned in L3 mode
|
||||
assert.Equal(t, c1.NetworkSettings.Networks[netName].Gateway, "")
|
||||
// Inspect the v6 gateway to ensure the explicitly specified default GW is ignored per L3 mode enabled
|
||||
assert.Equal(t, c1.NetworkSettings.Networks[netName].IPv6Gateway, "")
|
||||
// Inspect the v4 gateway to ensure no next hop is assigned in L3 mode
|
||||
assert.Equal(t, c3.NetworkSettings.Networks[netName].Gateway, "")
|
||||
// Inspect the v6 gateway to ensure the explicitly specified default GW is ignored per L3 mode enabled
|
||||
assert.Equal(t, c3.NetworkSettings.Networks[netName].IPv6Gateway, "")
|
||||
}
|
||||
}
|
||||
|
||||
func testIpvlanAddressing(client dclient.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
// Verify ipvlan l2 mode sets the proper default gateway routes via netlink
|
||||
// for either an explicitly set route by the user or inferred via default IPAM
|
||||
netNameL2 := "dualstackl2"
|
||||
net.CreateNoError(t, context.Background(), client, netNameL2,
|
||||
net.WithIPvlan("", "l2"),
|
||||
net.WithIPv6(),
|
||||
net.WithIPAM("172.28.140.0/24", "172.28.140.254"),
|
||||
net.WithIPAM("2001:db8:abcb::/64", ""),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netNameL2))
|
||||
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netNameL2),
|
||||
)
|
||||
// Validate ipvlan l2 mode defaults gateway sets the default IPAM next-hop inferred from the subnet
|
||||
result, err := container.Exec(ctx, client, id1, []string{"ip", "route"})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, strings.Contains(result.Combined(), "default via 172.28.140.254 dev eth0"))
|
||||
// Validate ipvlan l2 mode sets the v6 gateway to the user specified default gateway/next-hop
|
||||
result, err = container.Exec(ctx, client, id1, []string{"ip", "-6", "route"})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, strings.Contains(result.Combined(), "default via 2001:db8:abcb::1 dev eth0"))
|
||||
|
||||
// Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops
|
||||
netNameL3 := "dualstackl3"
|
||||
net.CreateNoError(t, context.Background(), client, netNameL3,
|
||||
net.WithIPvlan("", "l3"),
|
||||
net.WithIPv6(),
|
||||
net.WithIPAM("172.28.160.0/24", "172.28.160.254"),
|
||||
net.WithIPAM("2001:db8:abcd::/64", "2001:db8:abcd::254"),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netNameL3))
|
||||
|
||||
id2 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode(netNameL3),
|
||||
)
|
||||
// Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops
|
||||
result, err = container.Exec(ctx, client, id2, []string{"ip", "route"})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, strings.Contains(result.Combined(), "default dev eth0"))
|
||||
// Validate ipvlan l3 mode sets the v6 gateway to dev eth0 and disregards any explicit or inferred next-hops
|
||||
result, err = container.Exec(ctx, client, id2, []string{"ip", "-6", "route"})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, strings.Contains(result.Combined(), "default dev eth0"))
|
||||
}
|
||||
}
|
||||
|
||||
// ensure Kernel version is >= v4.2 for ipvlan support
|
||||
func ipvlanKernelSupport() bool {
|
||||
return n.CheckKernelMajorVersionGreaterOrEqualThen(4, 2)
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/network/ipvlan/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/network/ipvlan/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package ipvlan // import "github.com/docker/docker/integration/network/ipvlan"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
281
vendor/github.com/docker/docker-ce/components/engine/integration/network/macvlan/macvlan_test.go
generated
vendored
Normal file
281
vendor/github.com/docker/docker-ce/components/engine/integration/network/macvlan/macvlan_test.go
generated
vendored
Normal file
|
@ -0,0 +1,281 @@
|
|||
package macvlan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
net "github.com/docker/docker/integration/internal/network"
|
||||
n "github.com/docker/docker/integration/network"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestDockerNetworkMacvlanPersistance(t *testing.T) {
|
||||
// verify the driver automatically provisions the 802.1q link (dm-dummy0.60)
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
skip.If(t, !macvlanKernelSupport(), "Kernel doesn't support macvlan")
|
||||
|
||||
d := daemon.New(t)
|
||||
d.StartWithBusybox(t)
|
||||
defer d.Stop(t)
|
||||
|
||||
master := "dm-dummy0"
|
||||
n.CreateMasterDummy(t, master)
|
||||
defer n.DeleteInterface(t, master)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
netName := "dm-persist"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithMacvlan("dm-dummy0.60"),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
d.Restart(t)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
}
|
||||
|
||||
func TestDockerNetworkMacvlan(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
skip.If(t, !macvlanKernelSupport(), "Kernel doesn't support macvlan")
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
test func(client.APIClient) func(*testing.T)
|
||||
}{
|
||||
{
|
||||
name: "Subinterface",
|
||||
test: testMacvlanSubinterface,
|
||||
}, {
|
||||
name: "OverlapParent",
|
||||
test: testMacvlanOverlapParent,
|
||||
}, {
|
||||
name: "NilParent",
|
||||
test: testMacvlanNilParent,
|
||||
}, {
|
||||
name: "InternalMode",
|
||||
test: testMacvlanInternalMode,
|
||||
}, {
|
||||
name: "Addressing",
|
||||
test: testMacvlanAddressing,
|
||||
},
|
||||
} {
|
||||
d := daemon.New(t)
|
||||
d.StartWithBusybox(t)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
t.Run(tc.name, tc.test(client))
|
||||
|
||||
d.Stop(t)
|
||||
// FIXME(vdemeester) clean network
|
||||
}
|
||||
}
|
||||
|
||||
func testMacvlanOverlapParent(client client.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
// verify the same parent interface cannot be used if already in use by an existing network
|
||||
master := "dm-dummy0"
|
||||
n.CreateMasterDummy(t, master)
|
||||
defer n.DeleteInterface(t, master)
|
||||
|
||||
netName := "dm-subinterface"
|
||||
parentName := "dm-dummy0.40"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithMacvlan(parentName),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
_, err := net.Create(context.Background(), client, "dm-parent-net-overlap",
|
||||
net.WithMacvlan(parentName),
|
||||
)
|
||||
assert.Check(t, err != nil)
|
||||
|
||||
// delete the network while preserving the parent link
|
||||
err = client.NetworkRemove(context.Background(), netName)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, n.IsNetworkNotAvailable(client, netName))
|
||||
// verify the network delete did not delete the predefined link
|
||||
n.LinkExists(t, master)
|
||||
}
|
||||
}
|
||||
|
||||
func testMacvlanSubinterface(client client.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
// verify the same parent interface cannot be used if already in use by an existing network
|
||||
master := "dm-dummy0"
|
||||
parentName := "dm-dummy0.20"
|
||||
n.CreateMasterDummy(t, master)
|
||||
defer n.DeleteInterface(t, master)
|
||||
n.CreateVlanInterface(t, master, parentName, "20")
|
||||
|
||||
netName := "dm-subinterface"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithMacvlan(parentName),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
// delete the network while preserving the parent link
|
||||
err := client.NetworkRemove(context.Background(), netName)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, n.IsNetworkNotAvailable(client, netName))
|
||||
// verify the network delete did not delete the predefined link
|
||||
n.LinkExists(t, parentName)
|
||||
}
|
||||
}
|
||||
|
||||
func testMacvlanNilParent(client client.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
// macvlan bridge mode - dummy parent interface is provisioned dynamically
|
||||
netName := "dm-nil-parent"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithMacvlan(""),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
|
||||
id2 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
|
||||
|
||||
_, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1})
|
||||
assert.Check(t, err == nil)
|
||||
}
|
||||
}
|
||||
|
||||
func testMacvlanInternalMode(client client.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
// macvlan bridge mode - dummy parent interface is provisioned dynamically
|
||||
netName := "dm-internal"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithMacvlan(""),
|
||||
net.WithInternal(),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
|
||||
id2 := container.Run(t, ctx, client, container.WithNetworkMode(netName))
|
||||
|
||||
timeoutCtx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
_, err := container.Exec(timeoutCtx, client, id1, []string{"ping", "-c", "1", "-w", "1", "8.8.8.8"})
|
||||
// FIXME(vdemeester) check the time of error ?
|
||||
assert.Check(t, err != nil)
|
||||
assert.Check(t, timeoutCtx.Err() == context.DeadlineExceeded)
|
||||
|
||||
_, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1})
|
||||
assert.Check(t, err == nil)
|
||||
}
|
||||
}
|
||||
|
||||
func testMacvlanMultiSubnet(client client.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
netName := "dualstackbridge"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithMacvlan(""),
|
||||
net.WithIPv6(),
|
||||
net.WithIPAM("172.28.100.0/24", ""),
|
||||
net.WithIPAM("172.28.102.0/24", "172.28.102.254"),
|
||||
net.WithIPAM("2001:db8:abc2::/64", ""),
|
||||
net.WithIPAM("2001:db8:abc4::/64", "2001:db8:abc4::254"),
|
||||
)
|
||||
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.100.0/24 and 2001:db8:abc2::/64
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode("dualstackbridge"),
|
||||
container.WithIPv4("dualstackbridge", "172.28.100.20"),
|
||||
container.WithIPv6("dualstackbridge", "2001:db8:abc2::20"),
|
||||
)
|
||||
id2 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode("dualstackbridge"),
|
||||
container.WithIPv4("dualstackbridge", "172.28.100.21"),
|
||||
container.WithIPv6("dualstackbridge", "2001:db8:abc2::21"),
|
||||
)
|
||||
c1, err := client.ContainerInspect(ctx, id1)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// verify ipv4 connectivity to the explicit --ipv address second to first
|
||||
_, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", c1.NetworkSettings.Networks["dualstackbridge"].IPAddress})
|
||||
assert.NilError(t, err)
|
||||
// verify ipv6 connectivity to the explicit --ipv6 address second to first
|
||||
_, err = container.Exec(ctx, client, id2, []string{"ping6", "-c", "1", c1.NetworkSettings.Networks["dualstackbridge"].GlobalIPv6Address})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.102.0/24 and 2001:db8:abc4::/64
|
||||
id3 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode("dualstackbridge"),
|
||||
container.WithIPv4("dualstackbridge", "172.28.102.20"),
|
||||
container.WithIPv6("dualstackbridge", "2001:db8:abc4::20"),
|
||||
)
|
||||
id4 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode("dualstackbridge"),
|
||||
container.WithIPv4("dualstackbridge", "172.28.102.21"),
|
||||
container.WithIPv6("dualstackbridge", "2001:db8:abc4::21"),
|
||||
)
|
||||
c3, err := client.ContainerInspect(ctx, id3)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// verify ipv4 connectivity to the explicit --ipv address from third to fourth
|
||||
_, err = container.Exec(ctx, client, id4, []string{"ping", "-c", "1", c3.NetworkSettings.Networks["dualstackbridge"].IPAddress})
|
||||
assert.NilError(t, err)
|
||||
// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
|
||||
_, err = container.Exec(ctx, client, id4, []string{"ping6", "-c", "1", c3.NetworkSettings.Networks["dualstackbridge"].GlobalIPv6Address})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Inspect the v4 gateway to ensure the proper default GW was assigned
|
||||
assert.Equal(t, c1.NetworkSettings.Networks["dualstackbridge"].Gateway, "172.28.100.1")
|
||||
// Inspect the v6 gateway to ensure the proper default GW was assigned
|
||||
assert.Equal(t, c1.NetworkSettings.Networks["dualstackbridge"].IPv6Gateway, "2001:db8:abc2::1")
|
||||
// Inspect the v4 gateway to ensure the proper explicitly assigned default GW was assigned
|
||||
assert.Equal(t, c3.NetworkSettings.Networks["dualstackbridge"].Gateway, "172.28.102.254")
|
||||
// Inspect the v6 gateway to ensure the proper explicitly assigned default GW was assigned
|
||||
assert.Equal(t, c3.NetworkSettings.Networks["dualstackbridge"].IPv6Gateway, "2001:db8.abc4::254")
|
||||
}
|
||||
}
|
||||
|
||||
func testMacvlanAddressing(client client.APIClient) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
// Ensure the default gateways, next-hops and default dev devices are properly set
|
||||
netName := "dualstackbridge"
|
||||
net.CreateNoError(t, context.Background(), client, netName,
|
||||
net.WithMacvlan(""),
|
||||
net.WithIPv6(),
|
||||
net.WithOption("macvlan_mode", "bridge"),
|
||||
net.WithIPAM("172.28.130.0/24", ""),
|
||||
net.WithIPAM("2001:db8:abca::/64", "2001:db8:abca::254"),
|
||||
)
|
||||
assert.Check(t, n.IsNetworkAvailable(client, netName))
|
||||
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client,
|
||||
container.WithNetworkMode("dualstackbridge"),
|
||||
)
|
||||
|
||||
// Validate macvlan bridge mode defaults gateway sets the default IPAM next-hop inferred from the subnet
|
||||
result, err := container.Exec(ctx, client, id1, []string{"ip", "route"})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, strings.Contains(result.Combined(), "default via 172.28.130.1 dev eth0"))
|
||||
// Validate macvlan bridge mode sets the v6 gateway to the user specified default gateway/next-hop
|
||||
result, err = container.Exec(ctx, client, id1, []string{"ip", "-6", "route"})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, strings.Contains(result.Combined(), "default via 2001:db8:abca::254 dev eth0"))
|
||||
}
|
||||
}
|
||||
|
||||
// ensure Kernel version is >= v3.9 for macvlan support
|
||||
func macvlanKernelSupport() bool {
|
||||
return n.CheckKernelMajorVersionGreaterOrEqualThen(3, 9)
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/network/macvlan/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/network/macvlan/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package macvlan // import "github.com/docker/docker/integration/network/macvlan"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/network/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/network/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package network // import "github.com/docker/docker/integration/network"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
58
vendor/github.com/docker/docker-ce/components/engine/integration/network/network_test.go
generated
vendored
Normal file
58
vendor/github.com/docker/docker-ce/components/engine/integration/network/network_test.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
package network // import "github.com/docker/docker/integration/network"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestRunContainerWithBridgeNone(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run")
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
skip.If(t, IsUserNamespace())
|
||||
|
||||
d := daemon.New(t)
|
||||
d.StartWithBusybox(t, "-b", "none")
|
||||
defer d.Stop(t)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.Check(t, err, "error creating client")
|
||||
|
||||
ctx := context.Background()
|
||||
id1 := container.Run(t, ctx, client)
|
||||
defer client.ContainerRemove(ctx, id1, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
result, err := container.Exec(ctx, client, id1, []string{"ip", "l"})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(false, strings.Contains(result.Combined(), "eth0")), "There shouldn't be eth0 in container in default(bridge) mode when bridge network is disabled")
|
||||
|
||||
id2 := container.Run(t, ctx, client, container.WithNetworkMode("bridge"))
|
||||
defer client.ContainerRemove(ctx, id2, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
result, err = container.Exec(ctx, client, id2, []string{"ip", "l"})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(false, strings.Contains(result.Combined(), "eth0")), "There shouldn't be eth0 in container in bridge mode when bridge network is disabled")
|
||||
|
||||
nsCommand := "ls -l /proc/self/ns/net | awk -F '->' '{print $2}'"
|
||||
cmd := exec.Command("sh", "-c", nsCommand)
|
||||
stdout := bytes.NewBuffer(nil)
|
||||
cmd.Stdout = stdout
|
||||
err = cmd.Run()
|
||||
assert.NilError(t, err, "Failed to get current process network namespace: %+v", err)
|
||||
|
||||
id3 := container.Run(t, ctx, client, container.WithNetworkMode("host"))
|
||||
defer client.ContainerRemove(ctx, id3, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
result, err = container.Exec(ctx, client, id3, []string{"sh", "-c", nsCommand})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(stdout.String(), result.Combined()), "The network namspace of container should be the same with host when --net=host and bridge network is disabled")
|
||||
}
|
362
vendor/github.com/docker/docker-ce/components/engine/integration/network/service_test.go
generated
vendored
Normal file
362
vendor/github.com/docker/docker-ce/components/engine/integration/network/service_test.go
generated
vendored
Normal file
|
@ -0,0 +1,362 @@
|
|||
package network // import "github.com/docker/docker/integration/network"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/network"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/icmd"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
// delInterface removes given network interface
|
||||
func delInterface(t *testing.T, ifName string) {
|
||||
icmd.RunCommand("ip", "link", "delete", ifName).Assert(t, icmd.Success)
|
||||
icmd.RunCommand("iptables", "-t", "nat", "--flush").Assert(t, icmd.Success)
|
||||
icmd.RunCommand("iptables", "--flush").Assert(t, icmd.Success)
|
||||
}
|
||||
|
||||
func TestDaemonRestartWithLiveRestore(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "skip test from new feature")
|
||||
d := daemon.New(t)
|
||||
defer d.Stop(t)
|
||||
d.Start(t)
|
||||
d.Restart(t, "--live-restore=true",
|
||||
"--default-address-pool", "base=175.30.0.0/16,size=16",
|
||||
"--default-address-pool", "base=175.33.0.0/16,size=24")
|
||||
|
||||
// Verify bridge network's subnet
|
||||
cli, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
defer cli.Close()
|
||||
out, err := cli.NetworkInspect(context.Background(), "bridge", types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
// Make sure docker0 doesn't get override with new IP in live restore case
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "172.18.0.0/16")
|
||||
}
|
||||
|
||||
func TestDaemonDefaultNetworkPools(t *testing.T) {
|
||||
// Remove docker0 bridge and the start daemon defining the predefined address pools
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "skip test from new feature")
|
||||
defaultNetworkBridge := "docker0"
|
||||
delInterface(t, defaultNetworkBridge)
|
||||
d := daemon.New(t)
|
||||
defer d.Stop(t)
|
||||
d.Start(t,
|
||||
"--default-address-pool", "base=175.30.0.0/16,size=16",
|
||||
"--default-address-pool", "base=175.33.0.0/16,size=24")
|
||||
|
||||
// Verify bridge network's subnet
|
||||
cli, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
defer cli.Close()
|
||||
out, err := cli.NetworkInspect(context.Background(), "bridge", types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "175.30.0.0/16")
|
||||
|
||||
// Create a bridge network and verify its subnet is the second default pool
|
||||
name := "elango" + t.Name()
|
||||
network.CreateNoError(t, context.Background(), cli, name,
|
||||
network.WithDriver("bridge"),
|
||||
)
|
||||
out, err = cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "175.33.0.0/24")
|
||||
|
||||
// Create a bridge network and verify its subnet is the third default pool
|
||||
name = "saanvi" + t.Name()
|
||||
network.CreateNoError(t, context.Background(), cli, name,
|
||||
network.WithDriver("bridge"),
|
||||
)
|
||||
out, err = cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "175.33.1.0/24")
|
||||
delInterface(t, defaultNetworkBridge)
|
||||
|
||||
}
|
||||
|
||||
func TestDaemonRestartWithExistingNetwork(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "skip test from new feature")
|
||||
defaultNetworkBridge := "docker0"
|
||||
d := daemon.New(t)
|
||||
d.Start(t)
|
||||
defer d.Stop(t)
|
||||
// Verify bridge network's subnet
|
||||
cli, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
defer cli.Close()
|
||||
|
||||
// Create a bridge network
|
||||
name := "elango" + t.Name()
|
||||
network.CreateNoError(t, context.Background(), cli, name,
|
||||
network.WithDriver("bridge"),
|
||||
)
|
||||
out, err := cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
networkip := out.IPAM.Config[0].Subnet
|
||||
|
||||
// Restart daemon with default address pool option
|
||||
d.Restart(t,
|
||||
"--default-address-pool", "base=175.30.0.0/16,size=16",
|
||||
"--default-address-pool", "base=175.33.0.0/16,size=24")
|
||||
|
||||
out1, err := cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, out1.IPAM.Config[0].Subnet, networkip)
|
||||
delInterface(t, defaultNetworkBridge)
|
||||
}
|
||||
|
||||
func TestDaemonRestartWithExistingNetworkWithDefaultPoolRange(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "skip test from new feature")
|
||||
defaultNetworkBridge := "docker0"
|
||||
d := daemon.New(t)
|
||||
d.Start(t)
|
||||
defer d.Stop(t)
|
||||
// Verify bridge network's subnet
|
||||
cli, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
defer cli.Close()
|
||||
|
||||
// Create a bridge network
|
||||
name := "elango" + t.Name()
|
||||
network.CreateNoError(t, context.Background(), cli, name,
|
||||
network.WithDriver("bridge"),
|
||||
)
|
||||
out, err := cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
networkip := out.IPAM.Config[0].Subnet
|
||||
|
||||
// Create a bridge network
|
||||
name = "sthira" + t.Name()
|
||||
network.CreateNoError(t, context.Background(), cli, name,
|
||||
network.WithDriver("bridge"),
|
||||
)
|
||||
out, err = cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
networkip2 := out.IPAM.Config[0].Subnet
|
||||
|
||||
// Restart daemon with default address pool option
|
||||
d.Restart(t,
|
||||
"--default-address-pool", "base=175.18.0.0/16,size=16",
|
||||
"--default-address-pool", "base=175.19.0.0/16,size=24")
|
||||
|
||||
// Create a bridge network
|
||||
name = "saanvi" + t.Name()
|
||||
network.CreateNoError(t, context.Background(), cli, name,
|
||||
network.WithDriver("bridge"),
|
||||
)
|
||||
out1, err := cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, out1.IPAM.Config[0].Subnet != networkip)
|
||||
assert.Check(t, out1.IPAM.Config[0].Subnet != networkip2)
|
||||
delInterface(t, defaultNetworkBridge)
|
||||
}
|
||||
|
||||
func TestDaemonWithBipAndDefaultNetworkPool(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "skip test from new feature")
|
||||
defaultNetworkBridge := "docker0"
|
||||
d := daemon.New(t)
|
||||
defer d.Stop(t)
|
||||
d.Start(t, "--bip=172.60.0.1/16",
|
||||
"--default-address-pool", "base=175.30.0.0/16,size=16",
|
||||
"--default-address-pool", "base=175.33.0.0/16,size=24")
|
||||
|
||||
// Verify bridge network's subnet
|
||||
cli, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
defer cli.Close()
|
||||
out, err := cli.NetworkInspect(context.Background(), "bridge", types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
// Make sure BIP IP doesn't get override with new default address pool .
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "172.60.0.1/16")
|
||||
delInterface(t, defaultNetworkBridge)
|
||||
}
|
||||
|
||||
func TestServiceWithPredefinedNetwork(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
hostName := "host"
|
||||
var instances uint64 = 1
|
||||
serviceName := "TestService" + t.Name()
|
||||
|
||||
serviceID := swarm.CreateService(t, d,
|
||||
swarm.ServiceWithReplicas(instances),
|
||||
swarm.ServiceWithName(serviceName),
|
||||
swarm.ServiceWithNetwork(hostName),
|
||||
)
|
||||
|
||||
poll.WaitOn(t, serviceRunningCount(client, serviceID, instances), swarm.ServicePoll)
|
||||
|
||||
_, _, err := client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.ServiceRemove(context.Background(), serviceID)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
const ingressNet = "ingress"
|
||||
|
||||
func TestServiceRemoveKeepsIngressNetwork(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
poll.WaitOn(t, swarmIngressReady(client), swarm.NetworkPoll)
|
||||
|
||||
var instances uint64 = 1
|
||||
|
||||
serviceID := swarm.CreateService(t, d,
|
||||
swarm.ServiceWithReplicas(instances),
|
||||
swarm.ServiceWithName(t.Name()+"-service"),
|
||||
swarm.ServiceWithEndpoint(&swarmtypes.EndpointSpec{
|
||||
Ports: []swarmtypes.PortConfig{
|
||||
{
|
||||
Protocol: swarmtypes.PortConfigProtocolTCP,
|
||||
TargetPort: 80,
|
||||
PublishMode: swarmtypes.PortConfigPublishModeIngress,
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
poll.WaitOn(t, serviceRunningCount(client, serviceID, instances), swarm.ServicePoll)
|
||||
|
||||
_, _, err := client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.ServiceRemove(context.Background(), serviceID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, serviceIsRemoved(client, serviceID), swarm.ServicePoll)
|
||||
poll.WaitOn(t, noServices(client), swarm.ServicePoll)
|
||||
|
||||
// Ensure that "ingress" is not removed or corrupted
|
||||
time.Sleep(10 * time.Second)
|
||||
netInfo, err := client.NetworkInspect(context.Background(), ingressNet, types.NetworkInspectOptions{
|
||||
Verbose: true,
|
||||
Scope: "swarm",
|
||||
})
|
||||
assert.NilError(t, err, "Ingress network was removed after removing service!")
|
||||
assert.Assert(t, len(netInfo.Containers) != 0, "No load balancing endpoints in ingress network")
|
||||
assert.Assert(t, len(netInfo.Peers) != 0, "No peers (including self) in ingress network")
|
||||
_, ok := netInfo.Containers["ingress-sbox"]
|
||||
assert.Assert(t, ok, "ingress-sbox not present in ingress network")
|
||||
}
|
||||
|
||||
func serviceRunningCount(client client.ServiceAPIClient, serviceID string, instances uint64) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
services, err := client.ServiceList(context.Background(), types.ServiceListOptions{})
|
||||
if err != nil {
|
||||
return poll.Error(err)
|
||||
}
|
||||
|
||||
if len(services) != int(instances) {
|
||||
return poll.Continue("Service count at %d waiting for %d", len(services), instances)
|
||||
}
|
||||
return poll.Success()
|
||||
}
|
||||
}
|
||||
|
||||
func swarmIngressReady(client client.NetworkAPIClient) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
netInfo, err := client.NetworkInspect(context.Background(), ingressNet, types.NetworkInspectOptions{
|
||||
Verbose: true,
|
||||
Scope: "swarm",
|
||||
})
|
||||
if err != nil {
|
||||
return poll.Error(err)
|
||||
}
|
||||
np := len(netInfo.Peers)
|
||||
nc := len(netInfo.Containers)
|
||||
if np == 0 || nc == 0 {
|
||||
return poll.Continue("ingress not ready: %d peers and %d containers", nc, np)
|
||||
}
|
||||
_, ok := netInfo.Containers["ingress-sbox"]
|
||||
if !ok {
|
||||
return poll.Continue("ingress not ready: does not contain the ingress-sbox")
|
||||
}
|
||||
return poll.Success()
|
||||
}
|
||||
}
|
||||
|
||||
func noServices(client client.ServiceAPIClient) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
services, err := client.ServiceList(context.Background(), types.ServiceListOptions{})
|
||||
switch {
|
||||
case err != nil:
|
||||
return poll.Error(err)
|
||||
case len(services) == 0:
|
||||
return poll.Success()
|
||||
default:
|
||||
return poll.Continue("Service count at %d waiting for 0", len(services))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceWithDefaultAddressPoolInit(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
var ops = []func(*daemon.Daemon){}
|
||||
ipAddr := []string{"20.20.0.0/16"}
|
||||
ops = append(ops, daemon.WithSwarmDefaultAddrPool(ipAddr))
|
||||
ops = append(ops, daemon.WithSwarmDefaultAddrPoolSubnetSize(24))
|
||||
d := swarm.NewSwarm(t, testEnv, ops...)
|
||||
|
||||
cli := d.NewClientT(t)
|
||||
defer cli.Close()
|
||||
|
||||
// Create a overlay network
|
||||
name := "saanvisthira" + t.Name()
|
||||
network.CreateNoError(t, context.Background(), cli, name,
|
||||
network.WithDriver("overlay"))
|
||||
|
||||
var instances uint64 = 1
|
||||
serviceName := "TestService" + t.Name()
|
||||
serviceID := swarm.CreateService(t, d,
|
||||
swarm.ServiceWithReplicas(instances),
|
||||
swarm.ServiceWithName(serviceName),
|
||||
swarm.ServiceWithNetwork(name),
|
||||
)
|
||||
|
||||
poll.WaitOn(t, serviceRunningCount(cli, serviceID, instances), swarm.ServicePoll)
|
||||
|
||||
_, _, err := cli.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
out, err := cli.NetworkInspect(context.Background(), name, types.NetworkInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, out.IPAM.Config[0].Subnet, "20.20.0.0/24")
|
||||
|
||||
err = cli.ServiceRemove(context.Background(), serviceID)
|
||||
assert.NilError(t, err)
|
||||
d.SwarmLeave(true)
|
||||
d.Stop(t)
|
||||
|
||||
// Clean up , set it back to original one to make sure other tests don't fail
|
||||
ipAddr = []string{"10.10.0.0/8"}
|
||||
ops = append(ops, daemon.WithSwarmDefaultAddrPool(ipAddr))
|
||||
ops = append(ops, daemon.WithSwarmDefaultAddrPoolSubnetSize(24))
|
||||
d = swarm.NewSwarm(t, testEnv, ops...)
|
||||
d.SwarmLeave(true)
|
||||
defer d.Stop(t)
|
||||
}
|
521
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/authz/authz_plugin_test.go
generated
vendored
Normal file
521
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/authz/authz_plugin_test.go
generated
vendored
Normal file
|
@ -0,0 +1,521 @@
|
|||
// +build !windows
|
||||
|
||||
package authz // import "github.com/docker/docker/integration/plugin/authz"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
eventtypes "github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/authorization"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
const (
|
||||
testAuthZPlugin = "authzplugin"
|
||||
unauthorizedMessage = "User unauthorized authz plugin"
|
||||
errorMessage = "something went wrong..."
|
||||
serverVersionAPI = "/version"
|
||||
)
|
||||
|
||||
var (
|
||||
alwaysAllowed = []string{"/_ping", "/info"}
|
||||
ctrl *authorizationController
|
||||
)
|
||||
|
||||
type authorizationController struct {
|
||||
reqRes authorization.Response // reqRes holds the plugin response to the initial client request
|
||||
resRes authorization.Response // resRes holds the plugin response to the daemon response
|
||||
versionReqCount int // versionReqCount counts the number of requests to the server version API endpoint
|
||||
versionResCount int // versionResCount counts the number of responses from the server version API endpoint
|
||||
requestsURIs []string // requestsURIs stores all request URIs that are sent to the authorization controller
|
||||
reqUser string
|
||||
resUser string
|
||||
}
|
||||
|
||||
func setupTestV1(t *testing.T) func() {
|
||||
ctrl = &authorizationController{}
|
||||
teardown := setupTest(t)
|
||||
|
||||
err := os.MkdirAll("/etc/docker/plugins", 0755)
|
||||
assert.NilError(t, err)
|
||||
|
||||
fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", testAuthZPlugin)
|
||||
err = ioutil.WriteFile(fileName, []byte(server.URL), 0644)
|
||||
assert.NilError(t, err)
|
||||
|
||||
return func() {
|
||||
err := os.RemoveAll("/etc/docker/plugins")
|
||||
assert.NilError(t, err)
|
||||
|
||||
teardown()
|
||||
ctrl = nil
|
||||
}
|
||||
}
|
||||
|
||||
// check for always allowed endpoints to not inhibit test framework functions
|
||||
func isAllowed(reqURI string) bool {
|
||||
for _, endpoint := range alwaysAllowed {
|
||||
if strings.HasSuffix(reqURI, endpoint) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestAuthZPluginAllowRequest(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
ctrl.reqRes.Allow = true
|
||||
ctrl.resRes.Allow = true
|
||||
d.StartWithBusybox(t, "--authorization-plugin="+testAuthZPlugin)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Ensure command successful
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
assertURIRecorded(t, ctrl.requestsURIs, "/containers/create")
|
||||
assertURIRecorded(t, ctrl.requestsURIs, fmt.Sprintf("/containers/%s/start", cID))
|
||||
|
||||
_, err = client.ServerVersion(ctx)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 1, ctrl.versionReqCount)
|
||||
assert.Equal(t, 1, ctrl.versionResCount)
|
||||
}
|
||||
|
||||
func TestAuthZPluginTLS(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
const (
|
||||
testDaemonHTTPSAddr = "tcp://localhost:4271"
|
||||
cacertPath = "../../testdata/https/ca.pem"
|
||||
serverCertPath = "../../testdata/https/server-cert.pem"
|
||||
serverKeyPath = "../../testdata/https/server-key.pem"
|
||||
clientCertPath = "../../testdata/https/client-cert.pem"
|
||||
clientKeyPath = "../../testdata/https/client-key.pem"
|
||||
)
|
||||
|
||||
d.Start(t,
|
||||
"--authorization-plugin="+testAuthZPlugin,
|
||||
"--tlsverify",
|
||||
"--tlscacert", cacertPath,
|
||||
"--tlscert", serverCertPath,
|
||||
"--tlskey", serverKeyPath,
|
||||
"-H", testDaemonHTTPSAddr)
|
||||
|
||||
ctrl.reqRes.Allow = true
|
||||
ctrl.resRes.Allow = true
|
||||
|
||||
client, err := newTLSAPIClient(testDaemonHTTPSAddr, cacertPath, clientCertPath, clientKeyPath)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServerVersion(context.Background())
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, "client", ctrl.reqUser)
|
||||
assert.Equal(t, "client", ctrl.resUser)
|
||||
}
|
||||
|
||||
func newTLSAPIClient(host, cacertPath, certPath, keyPath string) (client.APIClient, error) {
|
||||
dialer := &net.Dialer{
|
||||
KeepAlive: 30 * time.Second,
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
return client.NewClientWithOpts(
|
||||
client.WithTLSClientConfig(cacertPath, certPath, keyPath),
|
||||
client.WithDialer(dialer),
|
||||
client.WithHost(host))
|
||||
}
|
||||
|
||||
func TestAuthZPluginDenyRequest(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
d.Start(t, "--authorization-plugin="+testAuthZPlugin)
|
||||
ctrl.reqRes.Allow = false
|
||||
ctrl.reqRes.Msg = unauthorizedMessage
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Ensure command is blocked
|
||||
_, err = client.ServerVersion(context.Background())
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Equal(t, 1, ctrl.versionReqCount)
|
||||
assert.Equal(t, 0, ctrl.versionResCount)
|
||||
|
||||
// Ensure unauthorized message appears in response
|
||||
assert.Equal(t, fmt.Sprintf("Error response from daemon: authorization denied by plugin %s: %s", testAuthZPlugin, unauthorizedMessage), err.Error())
|
||||
}
|
||||
|
||||
// TestAuthZPluginAPIDenyResponse validates that when authorization
|
||||
// plugin deny the request, the status code is forbidden
|
||||
func TestAuthZPluginAPIDenyResponse(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
d.Start(t, "--authorization-plugin="+testAuthZPlugin)
|
||||
ctrl.reqRes.Allow = false
|
||||
ctrl.resRes.Msg = unauthorizedMessage
|
||||
|
||||
daemonURL, err := url.Parse(d.Sock())
|
||||
assert.NilError(t, err)
|
||||
|
||||
conn, err := net.DialTimeout(daemonURL.Scheme, daemonURL.Path, time.Second*10)
|
||||
assert.NilError(t, err)
|
||||
client := httputil.NewClientConn(conn, nil)
|
||||
req, err := http.NewRequest("GET", "/version", nil)
|
||||
assert.NilError(t, err)
|
||||
resp, err := client.Do(req)
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, http.StatusForbidden, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestAuthZPluginDenyResponse(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
d.Start(t, "--authorization-plugin="+testAuthZPlugin)
|
||||
ctrl.reqRes.Allow = true
|
||||
ctrl.resRes.Allow = false
|
||||
ctrl.resRes.Msg = unauthorizedMessage
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Ensure command is blocked
|
||||
_, err = client.ServerVersion(context.Background())
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Equal(t, 1, ctrl.versionReqCount)
|
||||
assert.Equal(t, 1, ctrl.versionResCount)
|
||||
|
||||
// Ensure unauthorized message appears in response
|
||||
assert.Equal(t, fmt.Sprintf("Error response from daemon: authorization denied by plugin %s: %s", testAuthZPlugin, unauthorizedMessage), err.Error())
|
||||
}
|
||||
|
||||
// TestAuthZPluginAllowEventStream verifies event stream propagates
|
||||
// correctly after request pass through by the authorization plugin
|
||||
func TestAuthZPluginAllowEventStream(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTestV1(t)()
|
||||
ctrl.reqRes.Allow = true
|
||||
ctrl.resRes.Allow = true
|
||||
d.StartWithBusybox(t, "--authorization-plugin="+testAuthZPlugin)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
startTime := strconv.FormatInt(systemTime(t, client, testEnv).Unix(), 10)
|
||||
events, errs, cancel := systemEventsSince(client, startTime)
|
||||
defer cancel()
|
||||
|
||||
// Create a container and wait for the creation events
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
c, err := client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
if c.State.Running {
|
||||
break
|
||||
}
|
||||
if i == 99 {
|
||||
t.Fatal("Container didn't run within 10s")
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
created := false
|
||||
started := false
|
||||
for !created && !started {
|
||||
select {
|
||||
case event := <-events:
|
||||
if event.Type == eventtypes.ContainerEventType && event.Actor.ID == cID {
|
||||
if event.Action == "create" {
|
||||
created = true
|
||||
}
|
||||
if event.Action == "start" {
|
||||
started = true
|
||||
}
|
||||
}
|
||||
case err := <-errs:
|
||||
if err == io.EOF {
|
||||
t.Fatal("premature end of event stream")
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
case <-time.After(30 * time.Second):
|
||||
// Fail the test
|
||||
t.Fatal("event stream timeout")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure both events and container endpoints are passed to the
|
||||
// authorization plugin
|
||||
assertURIRecorded(t, ctrl.requestsURIs, "/events")
|
||||
assertURIRecorded(t, ctrl.requestsURIs, "/containers/create")
|
||||
assertURIRecorded(t, ctrl.requestsURIs, fmt.Sprintf("/containers/%s/start", cID))
|
||||
}
|
||||
|
||||
func systemTime(t *testing.T, client client.APIClient, testEnv *environment.Execution) time.Time {
|
||||
if testEnv.IsLocalDaemon() {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
info, err := client.Info(ctx)
|
||||
assert.NilError(t, err)
|
||||
|
||||
dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
|
||||
assert.NilError(t, err, "invalid time format in GET /info response")
|
||||
return dt
|
||||
}
|
||||
|
||||
func systemEventsSince(client client.APIClient, since string) (<-chan eventtypes.Message, <-chan error, func()) {
|
||||
eventOptions := types.EventsOptions{
|
||||
Since: since,
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
events, errs := client.Events(ctx, eventOptions)
|
||||
|
||||
return events, errs, cancel
|
||||
}
|
||||
|
||||
func TestAuthZPluginErrorResponse(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
d.Start(t, "--authorization-plugin="+testAuthZPlugin)
|
||||
ctrl.reqRes.Allow = true
|
||||
ctrl.resRes.Err = errorMessage
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Ensure command is blocked
|
||||
_, err = client.ServerVersion(context.Background())
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Equal(t, fmt.Sprintf("Error response from daemon: plugin %s failed with error: %s: %s", testAuthZPlugin, authorization.AuthZApiResponse, errorMessage), err.Error())
|
||||
}
|
||||
|
||||
func TestAuthZPluginErrorRequest(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
d.Start(t, "--authorization-plugin="+testAuthZPlugin)
|
||||
ctrl.reqRes.Err = errorMessage
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Ensure command is blocked
|
||||
_, err = client.ServerVersion(context.Background())
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Equal(t, fmt.Sprintf("Error response from daemon: plugin %s failed with error: %s: %s", testAuthZPlugin, authorization.AuthZApiRequest, errorMessage), err.Error())
|
||||
}
|
||||
|
||||
func TestAuthZPluginEnsureNoDuplicatePluginRegistration(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
d.Start(t, "--authorization-plugin="+testAuthZPlugin, "--authorization-plugin="+testAuthZPlugin)
|
||||
|
||||
ctrl.reqRes.Allow = true
|
||||
ctrl.resRes.Allow = true
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ServerVersion(context.Background())
|
||||
assert.NilError(t, err)
|
||||
|
||||
// assert plugin is only called once..
|
||||
assert.Equal(t, 1, ctrl.versionReqCount)
|
||||
assert.Equal(t, 1, ctrl.versionResCount)
|
||||
}
|
||||
|
||||
func TestAuthZPluginEnsureLoadImportWorking(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
ctrl.reqRes.Allow = true
|
||||
ctrl.resRes.Allow = true
|
||||
d.StartWithBusybox(t, "--authorization-plugin="+testAuthZPlugin, "--authorization-plugin="+testAuthZPlugin)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
tmp, err := ioutil.TempDir("", "test-authz-load-import")
|
||||
assert.NilError(t, err)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
savedImagePath := filepath.Join(tmp, "save.tar")
|
||||
|
||||
err = imageSave(client, savedImagePath, "busybox")
|
||||
assert.NilError(t, err)
|
||||
err = imageLoad(client, savedImagePath)
|
||||
assert.NilError(t, err)
|
||||
|
||||
exportedImagePath := filepath.Join(tmp, "export.tar")
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
responseReader, err := client.ContainerExport(context.Background(), cID)
|
||||
assert.NilError(t, err)
|
||||
defer responseReader.Close()
|
||||
file, err := os.Create(exportedImagePath)
|
||||
assert.NilError(t, err)
|
||||
defer file.Close()
|
||||
_, err = io.Copy(file, responseReader)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = imageImport(client, exportedImagePath)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestAuthzPluginEnsureContainerCopyToFrom(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
ctrl.reqRes.Allow = true
|
||||
ctrl.resRes.Allow = true
|
||||
d.StartWithBusybox(t, "--authorization-plugin="+testAuthZPlugin, "--authorization-plugin="+testAuthZPlugin)
|
||||
|
||||
dir, err := ioutil.TempDir("", t.Name())
|
||||
assert.Assert(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
f, err := ioutil.TempFile(dir, "send")
|
||||
assert.Assert(t, err)
|
||||
defer f.Close()
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
fileSize := len(buf) * 1024 * 10
|
||||
for written := 0; written < fileSize; {
|
||||
n, err := f.Write(buf)
|
||||
assert.Assert(t, err)
|
||||
written += n
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
client, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
defer client.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
_, err = f.Seek(0, io.SeekStart)
|
||||
assert.Assert(t, err)
|
||||
|
||||
srcInfo, err := archive.CopyInfoSourcePath(f.Name(), false)
|
||||
assert.Assert(t, err)
|
||||
srcArchive, err := archive.TarResource(srcInfo)
|
||||
assert.Assert(t, err)
|
||||
defer srcArchive.Close()
|
||||
|
||||
dstDir, preparedArchive, err := archive.PrepareArchiveCopy(srcArchive, srcInfo, archive.CopyInfo{Path: "/test"})
|
||||
assert.Assert(t, err)
|
||||
|
||||
err = client.CopyToContainer(ctx, cID, dstDir, preparedArchive, types.CopyToContainerOptions{})
|
||||
assert.Assert(t, err)
|
||||
|
||||
rdr, _, err := client.CopyFromContainer(ctx, cID, "/test")
|
||||
assert.Assert(t, err)
|
||||
_, err = io.Copy(ioutil.Discard, rdr)
|
||||
assert.Assert(t, err)
|
||||
}
|
||||
|
||||
func imageSave(client client.APIClient, path, image string) error {
|
||||
ctx := context.Background()
|
||||
responseReader, err := client.ImageSave(ctx, []string{image})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseReader.Close()
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = io.Copy(file, responseReader)
|
||||
return err
|
||||
}
|
||||
|
||||
func imageLoad(client client.APIClient, path string) error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
quiet := true
|
||||
ctx := context.Background()
|
||||
response, err := client.ImageLoad(ctx, file, quiet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func imageImport(client client.APIClient, path string) error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
options := types.ImageImportOptions{}
|
||||
ref := ""
|
||||
source := types.ImageImportSource{
|
||||
Source: file,
|
||||
SourceName: "-",
|
||||
}
|
||||
ctx := context.Background()
|
||||
responseReader, err := client.ImageImport(ctx, source, ref, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseReader.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestAuthZPluginHeader(t *testing.T) {
|
||||
defer setupTestV1(t)()
|
||||
ctrl.reqRes.Allow = true
|
||||
ctrl.resRes.Allow = true
|
||||
d.StartWithBusybox(t, "--debug", "--authorization-plugin="+testAuthZPlugin)
|
||||
|
||||
daemonURL, err := url.Parse(d.Sock())
|
||||
assert.NilError(t, err)
|
||||
|
||||
conn, err := net.DialTimeout(daemonURL.Scheme, daemonURL.Path, time.Second*10)
|
||||
assert.NilError(t, err)
|
||||
client := httputil.NewClientConn(conn, nil)
|
||||
req, err := http.NewRequest("GET", "/version", nil)
|
||||
assert.NilError(t, err)
|
||||
resp, err := client.Do(req)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, "application/json", resp.Header["Content-Type"][0])
|
||||
}
|
||||
|
||||
// assertURIRecorded verifies that the given URI was sent and recorded
|
||||
// in the authz plugin
|
||||
func assertURIRecorded(t *testing.T, uris []string, uri string) {
|
||||
var found bool
|
||||
for _, u := range uris {
|
||||
if strings.Contains(u, uri) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("Expected to find URI '%s', recorded uris '%s'", uri, strings.Join(uris, ","))
|
||||
}
|
||||
}
|
175
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/authz/authz_plugin_v2_test.go
generated
vendored
Normal file
175
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/authz/authz_plugin_v2_test.go
generated
vendored
Normal file
|
@ -0,0 +1,175 @@
|
|||
// +build !windows
|
||||
|
||||
package authz // import "github.com/docker/docker/integration/plugin/authz"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
volumetypes "github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/integration/internal/requirement"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
var (
|
||||
authzPluginName = "riyaz/authz-no-volume-plugin"
|
||||
authzPluginTag = "latest"
|
||||
authzPluginNameWithTag = authzPluginName + ":" + authzPluginTag
|
||||
authzPluginBadManifestName = "riyaz/authz-plugin-bad-manifest"
|
||||
nonexistentAuthzPluginName = "riyaz/nonexistent-authz-plugin"
|
||||
)
|
||||
|
||||
func setupTestV2(t *testing.T) func() {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
skip.If(t, !requirement.HasHubConnectivity(t))
|
||||
|
||||
teardown := setupTest(t)
|
||||
|
||||
d.Start(t)
|
||||
|
||||
return teardown
|
||||
}
|
||||
|
||||
func TestAuthZPluginV2AllowNonVolumeRequest(t *testing.T) {
|
||||
skip.If(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64")
|
||||
defer setupTestV2(t)()
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Install authz plugin
|
||||
err = pluginInstallGrantAllPermissions(client, authzPluginNameWithTag)
|
||||
assert.NilError(t, err)
|
||||
// start the daemon with the plugin and load busybox, --net=none build fails otherwise
|
||||
// because it needs to pull busybox
|
||||
d.Restart(t, "--authorization-plugin="+authzPluginNameWithTag)
|
||||
d.LoadBusybox(t)
|
||||
|
||||
// Ensure docker run command and accompanying docker ps are successful
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
_, err = client.ContainerInspect(ctx, cID)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestAuthZPluginV2Disable(t *testing.T) {
|
||||
skip.If(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64")
|
||||
defer setupTestV2(t)()
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Install authz plugin
|
||||
err = pluginInstallGrantAllPermissions(client, authzPluginNameWithTag)
|
||||
assert.NilError(t, err)
|
||||
|
||||
d.Restart(t, "--authorization-plugin="+authzPluginNameWithTag)
|
||||
d.LoadBusybox(t)
|
||||
|
||||
_, err = client.VolumeCreate(context.Background(), volumetypes.VolumeCreateBody{Driver: "local"})
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
|
||||
|
||||
// disable the plugin
|
||||
err = client.PluginDisable(context.Background(), authzPluginNameWithTag, types.PluginDisableOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// now test to see if the docker api works.
|
||||
_, err = client.VolumeCreate(context.Background(), volumetypes.VolumeCreateBody{Driver: "local"})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestAuthZPluginV2RejectVolumeRequests(t *testing.T) {
|
||||
skip.If(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64")
|
||||
defer setupTestV2(t)()
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Install authz plugin
|
||||
err = pluginInstallGrantAllPermissions(client, authzPluginNameWithTag)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// restart the daemon with the plugin
|
||||
d.Restart(t, "--authorization-plugin="+authzPluginNameWithTag)
|
||||
|
||||
_, err = client.VolumeCreate(context.Background(), volumetypes.VolumeCreateBody{Driver: "local"})
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
|
||||
|
||||
_, err = client.VolumeList(context.Background(), filters.Args{})
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
|
||||
|
||||
// The plugin will block the command before it can determine the volume does not exist
|
||||
err = client.VolumeRemove(context.Background(), "test", false)
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
|
||||
|
||||
_, err = client.VolumeInspect(context.Background(), "test")
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
|
||||
|
||||
_, err = client.VolumesPrune(context.Background(), filters.Args{})
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, strings.Contains(err.Error(), fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag)))
|
||||
}
|
||||
|
||||
func TestAuthZPluginV2BadManifestFailsDaemonStart(t *testing.T) {
|
||||
skip.If(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64")
|
||||
defer setupTestV2(t)()
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Install authz plugin with bad manifest
|
||||
err = pluginInstallGrantAllPermissions(client, authzPluginBadManifestName)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// start the daemon with the plugin, it will error
|
||||
err = d.RestartWithError("--authorization-plugin=" + authzPluginBadManifestName)
|
||||
assert.Assert(t, err != nil)
|
||||
|
||||
// restarting the daemon without requiring the plugin will succeed
|
||||
d.Start(t)
|
||||
}
|
||||
|
||||
func TestAuthZPluginV2NonexistentFailsDaemonStart(t *testing.T) {
|
||||
defer setupTestV2(t)()
|
||||
|
||||
// start the daemon with a non-existent authz plugin, it will error
|
||||
err := d.RestartWithError("--authorization-plugin=" + nonexistentAuthzPluginName)
|
||||
assert.Assert(t, err != nil)
|
||||
|
||||
// restarting the daemon without requiring the plugin will succeed
|
||||
d.Start(t)
|
||||
}
|
||||
|
||||
func pluginInstallGrantAllPermissions(client client.APIClient, name string) error {
|
||||
ctx := context.Background()
|
||||
options := types.PluginInstallOptions{
|
||||
RemoteRef: name,
|
||||
AcceptAllPermissions: true,
|
||||
}
|
||||
responseReader, err := client.PluginInstall(ctx, "", options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseReader.Close()
|
||||
// we have to read the response out here because the client API
|
||||
// actually starts a goroutine which we can only be sure has
|
||||
// completed when we get EOF from reading responseBody
|
||||
_, err = ioutil.ReadAll(responseReader)
|
||||
return err
|
||||
}
|
180
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/authz/main_test.go
generated
vendored
Normal file
180
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/authz/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
// +build !windows
|
||||
|
||||
package authz // import "github.com/docker/docker/integration/plugin/authz"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
"github.com/docker/docker/pkg/authorization"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
var (
|
||||
testEnv *environment.Execution
|
||||
d *daemon.Daemon
|
||||
server *httptest.Server
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
setupSuite()
|
||||
exitCode := m.Run()
|
||||
teardownSuite()
|
||||
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
|
||||
environment.ProtectAll(t, testEnv)
|
||||
|
||||
d = daemon.New(t, daemon.WithExperimental)
|
||||
|
||||
return func() {
|
||||
if d != nil {
|
||||
d.Stop(t)
|
||||
}
|
||||
testEnv.Clean(t)
|
||||
}
|
||||
}
|
||||
|
||||
func setupSuite() {
|
||||
mux := http.NewServeMux()
|
||||
server = httptest.NewServer(mux)
|
||||
|
||||
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
||||
b, err := json.Marshal(plugins.Manifest{Implements: []string{authorization.AuthZApiImplements}})
|
||||
if err != nil {
|
||||
panic("could not marshal json for /Plugin.Activate: " + err.Error())
|
||||
}
|
||||
w.Write(b)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/AuthZPlugin.AuthZReq", func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
panic("could not read body for /AuthZPlugin.AuthZReq: " + err.Error())
|
||||
}
|
||||
authReq := authorization.Request{}
|
||||
err = json.Unmarshal(body, &authReq)
|
||||
if err != nil {
|
||||
panic("could not unmarshal json for /AuthZPlugin.AuthZReq: " + err.Error())
|
||||
}
|
||||
|
||||
assertBody(authReq.RequestURI, authReq.RequestHeaders, authReq.RequestBody)
|
||||
assertAuthHeaders(authReq.RequestHeaders)
|
||||
|
||||
// Count only server version api
|
||||
if strings.HasSuffix(authReq.RequestURI, serverVersionAPI) {
|
||||
ctrl.versionReqCount++
|
||||
}
|
||||
|
||||
ctrl.requestsURIs = append(ctrl.requestsURIs, authReq.RequestURI)
|
||||
|
||||
reqRes := ctrl.reqRes
|
||||
if isAllowed(authReq.RequestURI) {
|
||||
reqRes = authorization.Response{Allow: true}
|
||||
}
|
||||
if reqRes.Err != "" {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
b, err := json.Marshal(reqRes)
|
||||
if err != nil {
|
||||
panic("could not marshal json for /AuthZPlugin.AuthZReq: " + err.Error())
|
||||
}
|
||||
|
||||
ctrl.reqUser = authReq.User
|
||||
w.Write(b)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/AuthZPlugin.AuthZRes", func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
panic("could not read body for /AuthZPlugin.AuthZRes: " + err.Error())
|
||||
}
|
||||
authReq := authorization.Request{}
|
||||
err = json.Unmarshal(body, &authReq)
|
||||
if err != nil {
|
||||
panic("could not unmarshal json for /AuthZPlugin.AuthZRes: " + err.Error())
|
||||
}
|
||||
|
||||
assertBody(authReq.RequestURI, authReq.ResponseHeaders, authReq.ResponseBody)
|
||||
assertAuthHeaders(authReq.ResponseHeaders)
|
||||
|
||||
// Count only server version api
|
||||
if strings.HasSuffix(authReq.RequestURI, serverVersionAPI) {
|
||||
ctrl.versionResCount++
|
||||
}
|
||||
resRes := ctrl.resRes
|
||||
if isAllowed(authReq.RequestURI) {
|
||||
resRes = authorization.Response{Allow: true}
|
||||
}
|
||||
if resRes.Err != "" {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
b, err := json.Marshal(resRes)
|
||||
if err != nil {
|
||||
panic("could not marshal json for /AuthZPlugin.AuthZRes: " + err.Error())
|
||||
}
|
||||
ctrl.resUser = authReq.User
|
||||
w.Write(b)
|
||||
})
|
||||
}
|
||||
|
||||
func teardownSuite() {
|
||||
if server == nil {
|
||||
return
|
||||
}
|
||||
|
||||
server.Close()
|
||||
}
|
||||
|
||||
// assertAuthHeaders validates authentication headers are removed
|
||||
func assertAuthHeaders(headers map[string]string) error {
|
||||
for k := range headers {
|
||||
if strings.Contains(strings.ToLower(k), "auth") || strings.Contains(strings.ToLower(k), "x-registry") {
|
||||
panic(fmt.Sprintf("Found authentication headers in request '%v'", headers))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// assertBody asserts that body is removed for non text/json requests
|
||||
func assertBody(requestURI string, headers map[string]string, body []byte) {
|
||||
if strings.Contains(strings.ToLower(requestURI), "auth") && len(body) > 0 {
|
||||
panic("Body included for authentication endpoint " + string(body))
|
||||
}
|
||||
|
||||
for k, v := range headers {
|
||||
if strings.EqualFold(k, "Content-Type") && strings.HasPrefix(v, "text/") || v == "application/json" {
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(body) > 0 {
|
||||
panic(fmt.Sprintf("Body included while it should not (Headers: '%v')", headers))
|
||||
}
|
||||
}
|
463
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/graphdriver/external_test.go
generated
vendored
Normal file
463
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/graphdriver/external_test.go
generated
vendored
Normal file
|
@ -0,0 +1,463 @@
|
|||
package graphdriver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/daemon/graphdriver/vfs"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/integration/internal/requirement"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
type graphEventsCounter struct {
|
||||
activations int
|
||||
creations int
|
||||
removals int
|
||||
gets int
|
||||
puts int
|
||||
stats int
|
||||
cleanups int
|
||||
exists int
|
||||
init int
|
||||
metadata int
|
||||
diff int
|
||||
applydiff int
|
||||
changes int
|
||||
diffsize int
|
||||
}
|
||||
|
||||
func TestExternalGraphDriver(t *testing.T) {
|
||||
skip.If(t, runtime.GOOS == "windows")
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
|
||||
skip.If(t, !requirement.HasHubConnectivity(t))
|
||||
|
||||
// Setup plugin(s)
|
||||
ec := make(map[string]*graphEventsCounter)
|
||||
sserver := setupPluginViaSpecFile(t, ec)
|
||||
jserver := setupPluginViaJSONFile(t, ec)
|
||||
// Create daemon
|
||||
d := daemon.New(t, daemon.WithExperimental)
|
||||
c := d.NewClientT(t)
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
test func(client.APIClient, *daemon.Daemon) func(*testing.T)
|
||||
}{
|
||||
{
|
||||
name: "json",
|
||||
test: testExternalGraphDriver("json", ec),
|
||||
},
|
||||
{
|
||||
name: "spec",
|
||||
test: testExternalGraphDriver("spec", ec),
|
||||
},
|
||||
{
|
||||
name: "pull",
|
||||
test: testGraphDriverPull,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, tc.test(c, d))
|
||||
}
|
||||
|
||||
sserver.Close()
|
||||
jserver.Close()
|
||||
err := os.RemoveAll("/etc/docker/plugins")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func setupPluginViaSpecFile(t *testing.T, ec map[string]*graphEventsCounter) *httptest.Server {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
|
||||
setupPlugin(t, ec, "spec", mux, []byte(server.URL))
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func setupPluginViaJSONFile(t *testing.T, ec map[string]*graphEventsCounter) *httptest.Server {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
|
||||
p := plugins.NewLocalPlugin("json-external-graph-driver", server.URL)
|
||||
b, err := json.Marshal(p)
|
||||
assert.NilError(t, err)
|
||||
|
||||
setupPlugin(t, ec, "json", mux, b)
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func setupPlugin(t *testing.T, ec map[string]*graphEventsCounter, ext string, mux *http.ServeMux, b []byte) {
|
||||
name := fmt.Sprintf("%s-external-graph-driver", ext)
|
||||
type graphDriverRequest struct {
|
||||
ID string `json:",omitempty"`
|
||||
Parent string `json:",omitempty"`
|
||||
MountLabel string `json:",omitempty"`
|
||||
ReadOnly bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
type graphDriverResponse struct {
|
||||
Err error `json:",omitempty"`
|
||||
Dir string `json:",omitempty"`
|
||||
Exists bool `json:",omitempty"`
|
||||
Status [][2]string `json:",omitempty"`
|
||||
Metadata map[string]string `json:",omitempty"`
|
||||
Changes []archive.Change `json:",omitempty"`
|
||||
Size int64 `json:",omitempty"`
|
||||
}
|
||||
|
||||
respond := func(w http.ResponseWriter, data interface{}) {
|
||||
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
||||
switch t := data.(type) {
|
||||
case error:
|
||||
fmt.Fprintln(w, fmt.Sprintf(`{"Err": %q}`, t.Error()))
|
||||
case string:
|
||||
fmt.Fprintln(w, t)
|
||||
default:
|
||||
json.NewEncoder(w).Encode(&data)
|
||||
}
|
||||
}
|
||||
|
||||
decReq := func(b io.ReadCloser, out interface{}, w http.ResponseWriter) error {
|
||||
defer b.Close()
|
||||
if err := json.NewDecoder(b).Decode(&out); err != nil {
|
||||
http.Error(w, fmt.Sprintf("error decoding json: %s", err.Error()), 500)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
base, err := ioutil.TempDir("", name)
|
||||
assert.NilError(t, err)
|
||||
vfsProto, err := vfs.Init(base, []string{}, nil, nil)
|
||||
assert.NilError(t, err, "error initializing graph driver")
|
||||
driver := graphdriver.NewNaiveDiffDriver(vfsProto, nil, nil)
|
||||
|
||||
ec[ext] = &graphEventsCounter{}
|
||||
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].activations++
|
||||
respond(w, `{"Implements": ["GraphDriver"]}`)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Init", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].init++
|
||||
respond(w, "{}")
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.CreateReadWrite", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].creations++
|
||||
|
||||
var req graphDriverRequest
|
||||
if err := decReq(r.Body, &req, w); err != nil {
|
||||
return
|
||||
}
|
||||
if err := driver.CreateReadWrite(req.ID, req.Parent, nil); err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, "{}")
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Create", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].creations++
|
||||
|
||||
var req graphDriverRequest
|
||||
if err := decReq(r.Body, &req, w); err != nil {
|
||||
return
|
||||
}
|
||||
if err := driver.Create(req.ID, req.Parent, nil); err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, "{}")
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Remove", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].removals++
|
||||
|
||||
var req graphDriverRequest
|
||||
if err := decReq(r.Body, &req, w); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := driver.Remove(req.ID); err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, "{}")
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Get", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].gets++
|
||||
|
||||
var req graphDriverRequest
|
||||
if err := decReq(r.Body, &req, w); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO @gupta-ak: Figure out what to do here.
|
||||
dir, err := driver.Get(req.ID, req.MountLabel)
|
||||
if err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, &graphDriverResponse{Dir: dir.Path()})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Put", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].puts++
|
||||
|
||||
var req graphDriverRequest
|
||||
if err := decReq(r.Body, &req, w); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := driver.Put(req.ID); err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, "{}")
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Exists", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].exists++
|
||||
|
||||
var req graphDriverRequest
|
||||
if err := decReq(r.Body, &req, w); err != nil {
|
||||
return
|
||||
}
|
||||
respond(w, &graphDriverResponse{Exists: driver.Exists(req.ID)})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Status", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].stats++
|
||||
respond(w, &graphDriverResponse{Status: driver.Status()})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Cleanup", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].cleanups++
|
||||
err := driver.Cleanup()
|
||||
if err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, `{}`)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.GetMetadata", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].metadata++
|
||||
|
||||
var req graphDriverRequest
|
||||
if err := decReq(r.Body, &req, w); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := driver.GetMetadata(req.ID)
|
||||
if err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, &graphDriverResponse{Metadata: data})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Diff", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].diff++
|
||||
|
||||
var req graphDriverRequest
|
||||
if err := decReq(r.Body, &req, w); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
diff, err := driver.Diff(req.ID, req.Parent)
|
||||
if err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
io.Copy(w, diff)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Changes", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].changes++
|
||||
var req graphDriverRequest
|
||||
if err := decReq(r.Body, &req, w); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
changes, err := driver.Changes(req.ID, req.Parent)
|
||||
if err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, &graphDriverResponse{Changes: changes})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.ApplyDiff", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].applydiff++
|
||||
diff := r.Body
|
||||
defer r.Body.Close()
|
||||
|
||||
id := r.URL.Query().Get("id")
|
||||
parent := r.URL.Query().Get("parent")
|
||||
|
||||
if id == "" {
|
||||
http.Error(w, fmt.Sprintf("missing id"), 409)
|
||||
}
|
||||
|
||||
size, err := driver.ApplyDiff(id, parent, diff)
|
||||
if err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, &graphDriverResponse{Size: size})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.DiffSize", func(w http.ResponseWriter, r *http.Request) {
|
||||
ec[ext].diffsize++
|
||||
|
||||
var req graphDriverRequest
|
||||
if err := decReq(r.Body, &req, w); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
size, err := driver.DiffSize(req.ID, req.Parent)
|
||||
if err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, &graphDriverResponse{Size: size})
|
||||
})
|
||||
|
||||
err = os.MkdirAll("/etc/docker/plugins", 0755)
|
||||
assert.NilError(t, err)
|
||||
|
||||
specFile := "/etc/docker/plugins/" + name + "." + ext
|
||||
err = ioutil.WriteFile(specFile, b, 0644)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func testExternalGraphDriver(ext string, ec map[string]*graphEventsCounter) func(client.APIClient, *daemon.Daemon) func(*testing.T) {
|
||||
return func(c client.APIClient, d *daemon.Daemon) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
driverName := fmt.Sprintf("%s-external-graph-driver", ext)
|
||||
d.StartWithBusybox(t, "-s", driverName)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
testGraphDriver(t, c, ctx, driverName, func(t *testing.T) {
|
||||
d.Restart(t, "-s", driverName)
|
||||
})
|
||||
|
||||
_, err := c.Info(ctx)
|
||||
assert.NilError(t, err)
|
||||
|
||||
d.Stop(t)
|
||||
|
||||
// Don't check ec.exists, because the daemon no longer calls the
|
||||
// Exists function.
|
||||
assert.Check(t, is.Equal(ec[ext].activations, 2))
|
||||
assert.Check(t, is.Equal(ec[ext].init, 2))
|
||||
assert.Check(t, ec[ext].creations >= 1)
|
||||
assert.Check(t, ec[ext].removals >= 1)
|
||||
assert.Check(t, ec[ext].gets >= 1)
|
||||
assert.Check(t, ec[ext].puts >= 1)
|
||||
assert.Check(t, is.Equal(ec[ext].stats, 5))
|
||||
assert.Check(t, is.Equal(ec[ext].cleanups, 2))
|
||||
assert.Check(t, ec[ext].applydiff >= 1)
|
||||
assert.Check(t, is.Equal(ec[ext].changes, 1))
|
||||
assert.Check(t, is.Equal(ec[ext].diffsize, 0))
|
||||
assert.Check(t, is.Equal(ec[ext].diff, 0))
|
||||
assert.Check(t, is.Equal(ec[ext].metadata, 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testGraphDriverPull(c client.APIClient, d *daemon.Daemon) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
d.Start(t)
|
||||
defer d.Stop(t)
|
||||
ctx := context.Background()
|
||||
|
||||
r, err := c.ImagePull(ctx, "busybox:latest@sha256:bbc3a03235220b170ba48a157dd097dd1379299370e1ed99ce976df0355d24f0", types.ImagePullOptions{})
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(ioutil.Discard, r)
|
||||
assert.NilError(t, err)
|
||||
|
||||
container.Run(t, ctx, c, container.WithImage("busybox:latest@sha256:bbc3a03235220b170ba48a157dd097dd1379299370e1ed99ce976df0355d24f0"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGraphdriverPluginV2(t *testing.T) {
|
||||
skip.If(t, runtime.GOOS == "windows")
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
|
||||
skip.If(t, !requirement.HasHubConnectivity(t))
|
||||
skip.If(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64")
|
||||
skip.If(t, !requirement.Overlay2Supported(testEnv.DaemonInfo.KernelVersion))
|
||||
|
||||
d := daemon.New(t, daemon.WithExperimental)
|
||||
d.Start(t)
|
||||
defer d.Stop(t)
|
||||
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
|
||||
// install the plugin
|
||||
plugin := "cpuguy83/docker-overlay2-graphdriver-plugin"
|
||||
responseReader, err := client.PluginInstall(ctx, plugin, types.PluginInstallOptions{
|
||||
RemoteRef: plugin,
|
||||
AcceptAllPermissions: true,
|
||||
})
|
||||
defer responseReader.Close()
|
||||
assert.NilError(t, err)
|
||||
// ensure it's done by waiting for EOF on the response
|
||||
_, err = io.Copy(ioutil.Discard, responseReader)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// restart the daemon with the plugin set as the storage driver
|
||||
d.Stop(t)
|
||||
d.StartWithBusybox(t, "-s", plugin, "--storage-opt", "overlay2.override_kernel_check=1")
|
||||
|
||||
testGraphDriver(t, client, ctx, plugin, nil)
|
||||
}
|
||||
|
||||
// nolint: golint
|
||||
func testGraphDriver(t *testing.T, c client.APIClient, ctx context.Context, driverName string, afterContainerRunFn func(*testing.T)) { //nolint: golint
|
||||
id := container.Run(t, ctx, c, container.WithCmd("sh", "-c", "echo hello > /hello"))
|
||||
|
||||
if afterContainerRunFn != nil {
|
||||
afterContainerRunFn(t)
|
||||
}
|
||||
|
||||
i, err := c.ContainerInspect(ctx, id)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(i.GraphDriver.Name, driverName))
|
||||
|
||||
diffs, err := c.ContainerDiff(ctx, id)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(diffs, containertypes.ContainerChangeResponseItem{
|
||||
Kind: archive.ChangeAdd,
|
||||
Path: "/hello",
|
||||
}), "diffs: %v", diffs)
|
||||
|
||||
err = c.ContainerRemove(ctx, id, types.ContainerRemoveOptions{
|
||||
Force: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
}
|
36
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/graphdriver/main_test.go
generated
vendored
Normal file
36
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/graphdriver/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
package graphdriver // import "github.com/docker/docker/integration/plugin/graphdriver"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
)
|
||||
|
||||
var (
|
||||
testEnv *environment.Execution
|
||||
)
|
||||
|
||||
func init() {
|
||||
reexec.Init() // This is required for external graphdriver tests
|
||||
}
|
||||
|
||||
const dockerdBinary = "dockerd"
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
48
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/cmd/close_on_start/main.go
generated
vendored
Normal file
48
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/cmd/close_on_start/main.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
type start struct {
|
||||
File string
|
||||
}
|
||||
|
||||
func main() {
|
||||
l, err := net.Listen("unix", "/run/docker/plugins/plugin.sock")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/LogDriver.StartLogging", func(w http.ResponseWriter, req *http.Request) {
|
||||
startReq := &start{}
|
||||
if err := json.NewDecoder(req.Body).Decode(startReq); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(startReq.File, os.O_RDONLY, 0600)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Close the file immediately, this allows us to test what happens in the daemon when the plugin has closed the
|
||||
// file or, for example, the plugin has crashed.
|
||||
f.Close()
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintln(w, `{}`)
|
||||
})
|
||||
server := http.Server{
|
||||
Addr: l.Addr().String(),
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
server.Serve(l)
|
||||
}
|
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/cmd/close_on_start/main_test.go
generated
vendored
Normal file
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/cmd/close_on_start/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
package main
|
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/cmd/cmd_test.go
generated
vendored
Normal file
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/cmd/cmd_test.go
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
package cmd
|
19
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/cmd/dummy/main.go
generated
vendored
Normal file
19
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/cmd/dummy/main.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l, err := net.Listen("unix", "/run/docker/plugins/plugin.sock")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
server := http.Server{
|
||||
Addr: l.Addr().String(),
|
||||
Handler: http.NewServeMux(),
|
||||
}
|
||||
server.Serve(l)
|
||||
}
|
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/cmd/dummy/main_test.go
generated
vendored
Normal file
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/cmd/dummy/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
package main
|
67
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/helpers_test.go
generated
vendored
Normal file
67
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/helpers_test.go
generated
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/internal/test/fixtures/plugin"
|
||||
"github.com/docker/docker/pkg/locker"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var pluginBuildLock = locker.New()
|
||||
|
||||
func ensurePlugin(t *testing.T, name string) string {
|
||||
pluginBuildLock.Lock(name)
|
||||
defer pluginBuildLock.Unlock(name)
|
||||
|
||||
installPath := filepath.Join(os.Getenv("GOPATH"), "bin", name)
|
||||
if _, err := os.Stat(installPath); err == nil {
|
||||
return installPath
|
||||
}
|
||||
|
||||
goBin, err := exec.LookPath("go")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(goBin, "build", "-o", installPath, "./"+filepath.Join("cmd", name))
|
||||
cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Fatal(errors.Wrapf(err, "error building basic plugin bin: %s", string(out)))
|
||||
}
|
||||
|
||||
return installPath
|
||||
}
|
||||
|
||||
func withSockPath(name string) func(*plugin.Config) {
|
||||
return func(cfg *plugin.Config) {
|
||||
cfg.Interface.Socket = name
|
||||
}
|
||||
}
|
||||
|
||||
func createPlugin(t *testing.T, client plugin.CreateClient, alias, bin string, opts ...plugin.CreateOpt) {
|
||||
pluginBin := ensurePlugin(t, bin)
|
||||
|
||||
opts = append(opts, withSockPath("plugin.sock"))
|
||||
opts = append(opts, plugin.WithBinary(pluginBin))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
err := plugin.Create(ctx, client, alias, opts...)
|
||||
cancel()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func asLogDriver(cfg *plugin.Config) {
|
||||
cfg.Interface.Types = []types.PluginInterfaceType{
|
||||
{Capability: "logdriver", Prefix: "docker", Version: "1.0"},
|
||||
}
|
||||
}
|
79
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/logging_test.go
generated
vendored
Normal file
79
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/logging_test.go
generated
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
package logging
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestContinueAfterPluginCrash(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon(), "test requires daemon on the same host")
|
||||
t.Parallel()
|
||||
|
||||
d := daemon.New(t)
|
||||
d.StartWithBusybox(t, "--iptables=false", "--init")
|
||||
defer d.Stop(t)
|
||||
|
||||
client := d.NewClientT(t)
|
||||
createPlugin(t, client, "test", "close_on_start", asLogDriver)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
assert.Assert(t, client.PluginEnable(ctx, "test", types.PluginEnableOptions{Timeout: 30}))
|
||||
cancel()
|
||||
defer client.PluginRemove(context.Background(), "test", types.PluginRemoveOptions{Force: true})
|
||||
|
||||
ctx, cancel = context.WithTimeout(context.Background(), 60*time.Second)
|
||||
|
||||
id := container.Run(t, ctx, client,
|
||||
container.WithAutoRemove,
|
||||
container.WithLogDriver("test"),
|
||||
container.WithCmd(
|
||||
"/bin/sh", "-c", "while true; do sleep 1; echo hello; done",
|
||||
),
|
||||
)
|
||||
cancel()
|
||||
defer client.ContainerRemove(context.Background(), id, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
// Attach to the container to make sure it's written a few times to stdout
|
||||
attach, err := client.ContainerAttach(context.Background(), id, types.ContainerAttachOptions{Stream: true, Stdout: true})
|
||||
assert.Assert(t, err)
|
||||
|
||||
chErr := make(chan error)
|
||||
go func() {
|
||||
defer close(chErr)
|
||||
rdr := bufio.NewReader(attach.Reader)
|
||||
for i := 0; i < 5; i++ {
|
||||
_, _, err := rdr.ReadLine()
|
||||
if err != nil {
|
||||
chErr <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-chErr:
|
||||
assert.Assert(t, err)
|
||||
case <-time.After(60 * time.Second):
|
||||
t.Fatal("timeout waiting for container i/o")
|
||||
}
|
||||
|
||||
// check daemon logs for "broken pipe"
|
||||
// TODO(@cpuguy83): This is horribly hacky but is the only way to really test this case right now.
|
||||
// It would be nice if there was a way to know that a broken pipe has occurred without looking through the logs.
|
||||
log, err := os.Open(d.LogFileName())
|
||||
assert.Assert(t, err)
|
||||
scanner := bufio.NewScanner(log)
|
||||
for scanner.Scan() {
|
||||
assert.Assert(t, !strings.Contains(scanner.Text(), "broken pipe"))
|
||||
}
|
||||
}
|
29
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/main_test.go
generated
vendored
Normal file
29
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
package logging // import "github.com/docker/docker/integration/plugin/logging"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var (
|
||||
testEnv *environment.Execution
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
35
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/validation_test.go
generated
vendored
Normal file
35
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/logging/validation_test.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
// Regression test for #35553
|
||||
// Ensure that a daemon with a log plugin set as the default logger for containers
|
||||
// does not keep the daemon from starting.
|
||||
func TestDaemonStartWithLogOpt(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
|
||||
t.Parallel()
|
||||
|
||||
d := daemon.New(t)
|
||||
d.Start(t, "--iptables=false")
|
||||
defer d.Stop(t)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.Check(t, err)
|
||||
ctx := context.Background()
|
||||
|
||||
createPlugin(t, client, "test", "dummy", asLogDriver)
|
||||
err = client.PluginEnable(ctx, "test", types.PluginEnableOptions{Timeout: 30})
|
||||
assert.Check(t, err)
|
||||
defer client.PluginRemove(ctx, "test", types.PluginRemoveOptions{Force: true})
|
||||
|
||||
d.Stop(t)
|
||||
d.Start(t, "--iptables=false", "--log-driver=test", "--log-opt=foo=bar")
|
||||
}
|
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/pkg_test.go
generated
vendored
Normal file
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/pkg_test.go
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
package plugin // import "github.com/docker/docker/integration/plugin"
|
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/cmd/cmd_test.go
generated
vendored
Normal file
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/cmd/cmd_test.go
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
package cmd
|
19
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/cmd/dummy/main.go
generated
vendored
Normal file
19
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/cmd/dummy/main.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l, err := net.Listen("unix", "/run/docker/plugins/plugin.sock")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
server := http.Server{
|
||||
Addr: l.Addr().String(),
|
||||
Handler: http.NewServeMux(),
|
||||
}
|
||||
server.Serve(l)
|
||||
}
|
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/cmd/dummy/main_test.go
generated
vendored
Normal file
1
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/cmd/dummy/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
package main
|
73
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/helpers_test.go
generated
vendored
Normal file
73
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/helpers_test.go
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
package volumes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/internal/test/fixtures/plugin"
|
||||
"github.com/docker/docker/pkg/locker"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var pluginBuildLock = locker.New()
|
||||
|
||||
// ensurePlugin makes the that a plugin binary has been installed on the system.
|
||||
// Plugins that have not been installed are built from `cmd/<name>`.
|
||||
func ensurePlugin(t *testing.T, name string) string {
|
||||
pluginBuildLock.Lock(name)
|
||||
defer pluginBuildLock.Unlock(name)
|
||||
|
||||
goPath := os.Getenv("GOPATH")
|
||||
if goPath == "" {
|
||||
goPath = "/go"
|
||||
}
|
||||
installPath := filepath.Join(goPath, "bin", name)
|
||||
if _, err := os.Stat(installPath); err == nil {
|
||||
return installPath
|
||||
}
|
||||
|
||||
goBin, err := exec.LookPath("go")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(goBin, "build", "-o", installPath, "./"+filepath.Join("cmd", name))
|
||||
cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Fatal(errors.Wrapf(err, "error building basic plugin bin: %s", string(out)))
|
||||
}
|
||||
|
||||
return installPath
|
||||
}
|
||||
|
||||
func withSockPath(name string) func(*plugin.Config) {
|
||||
return func(cfg *plugin.Config) {
|
||||
cfg.Interface.Socket = name
|
||||
}
|
||||
}
|
||||
|
||||
func createPlugin(t *testing.T, client plugin.CreateClient, alias, bin string, opts ...plugin.CreateOpt) {
|
||||
pluginBin := ensurePlugin(t, bin)
|
||||
|
||||
opts = append(opts, withSockPath("plugin.sock"))
|
||||
opts = append(opts, plugin.WithBinary(pluginBin))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
err := plugin.Create(ctx, client, alias, opts...)
|
||||
cancel()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func asVolumeDriver(cfg *plugin.Config) {
|
||||
cfg.Interface.Types = []types.PluginInterfaceType{
|
||||
{Capability: "volumedriver", Prefix: "docker", Version: "1.0"},
|
||||
}
|
||||
}
|
32
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/main_test.go
generated
vendored
Normal file
32
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
package volumes // import "github.com/docker/docker/integration/plugin/volumes"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var (
|
||||
testEnv *environment.Execution
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if testEnv.OSType != "linux" {
|
||||
os.Exit(0)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
58
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/mounts_test.go
generated
vendored
Normal file
58
vendor/github.com/docker/docker-ce/components/engine/integration/plugin/volumes/mounts_test.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
package volumes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/docker/docker/internal/test/fixtures/plugin"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
// TestPluginWithDevMounts tests very specific regression caused by mounts ordering
|
||||
// (sorted in the daemon). See #36698
|
||||
func TestPluginWithDevMounts(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
|
||||
t.Parallel()
|
||||
|
||||
d := daemon.New(t)
|
||||
d.Start(t, "--iptables=false")
|
||||
defer d.Stop(t)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.Assert(t, err)
|
||||
ctx := context.Background()
|
||||
|
||||
testDir, err := ioutil.TempDir("", "test-dir")
|
||||
assert.Assert(t, err)
|
||||
defer os.RemoveAll(testDir)
|
||||
|
||||
createPlugin(t, client, "test", "dummy", asVolumeDriver, func(c *plugin.Config) {
|
||||
root := "/"
|
||||
dev := "/dev"
|
||||
mounts := []types.PluginMount{
|
||||
{Type: "bind", Source: &root, Destination: "/host", Options: []string{"rbind"}},
|
||||
{Type: "bind", Source: &dev, Destination: "/dev", Options: []string{"rbind"}},
|
||||
{Type: "bind", Source: &testDir, Destination: "/etc/foo", Options: []string{"rbind"}},
|
||||
}
|
||||
c.PluginConfig.Mounts = append(c.PluginConfig.Mounts, mounts...)
|
||||
c.PropagatedMount = "/propagated"
|
||||
c.Network = types.PluginConfigNetwork{Type: "host"}
|
||||
c.IpcHost = true
|
||||
})
|
||||
|
||||
err = client.PluginEnable(ctx, "test", types.PluginEnableOptions{Timeout: 30})
|
||||
assert.Assert(t, err)
|
||||
defer func() {
|
||||
err := client.PluginRemove(ctx, "test", types.PluginRemoveOptions{Force: true})
|
||||
assert.Check(t, err)
|
||||
}()
|
||||
|
||||
p, _, err := client.PluginInspectWithRaw(ctx, "test")
|
||||
assert.Assert(t, err)
|
||||
assert.Assert(t, p.Enabled)
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/secret/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/secret/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package secret // import "github.com/docker/docker/integration/secret"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
366
vendor/github.com/docker/docker-ce/components/engine/integration/secret/secret_test.go
generated
vendored
Normal file
366
vendor/github.com/docker/docker-ce/components/engine/integration/secret/secret_test.go
generated
vendored
Normal file
|
@ -0,0 +1,366 @@
|
|||
package secret // import "github.com/docker/docker/integration/secret"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestSecretInspect(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
testName := "test_secret_" + t.Name()
|
||||
secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
|
||||
|
||||
secret, _, err := client.SecretInspectWithRaw(context.Background(), secretID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(secret.Spec.Name, testName))
|
||||
|
||||
secret, _, err = client.SecretInspectWithRaw(context.Background(), testName)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(secretID, secretID))
|
||||
}
|
||||
|
||||
func TestSecretList(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
|
||||
testName0 := "test0_" + t.Name()
|
||||
testName1 := "test1_" + t.Name()
|
||||
testNames := []string{testName0, testName1}
|
||||
sort.Strings(testNames)
|
||||
|
||||
// create secret test0
|
||||
createSecret(ctx, t, client, testName0, []byte("TESTINGDATA0"), map[string]string{"type": "test"})
|
||||
|
||||
// create secret test1
|
||||
secret1ID := createSecret(ctx, t, client, testName1, []byte("TESTINGDATA1"), map[string]string{"type": "production"})
|
||||
|
||||
names := func(entries []swarmtypes.Secret) []string {
|
||||
var values []string
|
||||
for _, entry := range entries {
|
||||
values = append(values, entry.Spec.Name)
|
||||
}
|
||||
sort.Strings(values)
|
||||
return values
|
||||
}
|
||||
|
||||
// test by `secret ls`
|
||||
entries, err := client.SecretList(ctx, types.SecretListOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(names(entries), testNames))
|
||||
|
||||
testCases := []struct {
|
||||
filters filters.Args
|
||||
expected []string
|
||||
}{
|
||||
// test filter by name `secret ls --filter name=xxx`
|
||||
{
|
||||
filters: filters.NewArgs(filters.Arg("name", testName0)),
|
||||
expected: []string{testName0},
|
||||
},
|
||||
// test filter by id `secret ls --filter id=xxx`
|
||||
{
|
||||
filters: filters.NewArgs(filters.Arg("id", secret1ID)),
|
||||
expected: []string{testName1},
|
||||
},
|
||||
// test filter by label `secret ls --filter label=xxx`
|
||||
{
|
||||
filters: filters.NewArgs(filters.Arg("label", "type")),
|
||||
expected: testNames,
|
||||
},
|
||||
{
|
||||
filters: filters.NewArgs(filters.Arg("label", "type=test")),
|
||||
expected: []string{testName0},
|
||||
},
|
||||
{
|
||||
filters: filters.NewArgs(filters.Arg("label", "type=production")),
|
||||
expected: []string{testName1},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
entries, err = client.SecretList(ctx, types.SecretListOptions{
|
||||
Filters: tc.filters,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(names(entries), tc.expected))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func createSecret(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string {
|
||||
secret, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: name,
|
||||
Labels: labels,
|
||||
},
|
||||
Data: data,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, secret.ID != "")
|
||||
return secret.ID
|
||||
}
|
||||
|
||||
func TestSecretsCreateAndDelete(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
|
||||
testName := "test_secret_" + t.Name()
|
||||
secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
|
||||
|
||||
// create an already existin secret, daemon should return a status code of 409
|
||||
_, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: testName,
|
||||
},
|
||||
Data: []byte("TESTINGDATA"),
|
||||
})
|
||||
assert.Check(t, is.ErrorContains(err, "already exists"))
|
||||
|
||||
// Ported from original TestSecretsDelete
|
||||
err = client.SecretRemove(ctx, secretID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, _, err = client.SecretInspectWithRaw(ctx, secretID)
|
||||
assert.Check(t, is.ErrorContains(err, "No such secret"))
|
||||
|
||||
err = client.SecretRemove(ctx, "non-existin")
|
||||
assert.Check(t, is.ErrorContains(err, "No such secret: non-existin"))
|
||||
|
||||
// Ported from original TestSecretsCreteaWithLabels
|
||||
testName = "test_secret_with_labels_" + t.Name()
|
||||
secretID = createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), map[string]string{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
})
|
||||
|
||||
insp, _, err := client.SecretInspectWithRaw(ctx, secretID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.Spec.Name, testName))
|
||||
assert.Check(t, is.Equal(len(insp.Spec.Labels), 2))
|
||||
assert.Check(t, is.Equal(insp.Spec.Labels["key1"], "value1"))
|
||||
assert.Check(t, is.Equal(insp.Spec.Labels["key2"], "value2"))
|
||||
}
|
||||
|
||||
func TestSecretsUpdate(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
|
||||
testName := "test_secret_" + t.Name()
|
||||
secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
|
||||
|
||||
insp, _, err := client.SecretInspectWithRaw(ctx, secretID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.ID, secretID))
|
||||
|
||||
// test UpdateSecret with full ID
|
||||
insp.Spec.Labels = map[string]string{"test": "test1"}
|
||||
err = client.SecretUpdate(ctx, secretID, insp.Version, insp.Spec)
|
||||
assert.NilError(t, err)
|
||||
|
||||
insp, _, err = client.SecretInspectWithRaw(ctx, secretID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test1"))
|
||||
|
||||
// test UpdateSecret with full name
|
||||
insp.Spec.Labels = map[string]string{"test": "test2"}
|
||||
err = client.SecretUpdate(ctx, testName, insp.Version, insp.Spec)
|
||||
assert.NilError(t, err)
|
||||
|
||||
insp, _, err = client.SecretInspectWithRaw(ctx, secretID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test2"))
|
||||
|
||||
// test UpdateSecret with prefix ID
|
||||
insp.Spec.Labels = map[string]string{"test": "test3"}
|
||||
err = client.SecretUpdate(ctx, secretID[:1], insp.Version, insp.Spec)
|
||||
assert.NilError(t, err)
|
||||
|
||||
insp, _, err = client.SecretInspectWithRaw(ctx, secretID)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test3"))
|
||||
|
||||
// test UpdateSecret in updating Data which is not supported in daemon
|
||||
// this test will produce an error in func UpdateSecret
|
||||
insp.Spec.Data = []byte("TESTINGDATA2")
|
||||
err = client.SecretUpdate(ctx, secretID, insp.Version, insp.Spec)
|
||||
assert.Check(t, is.ErrorContains(err, "only updates to Labels are allowed"))
|
||||
}
|
||||
|
||||
func TestTemplatedSecret(t *testing.T) {
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
|
||||
referencedSecretName := "referencedsecret_" + t.Name()
|
||||
referencedSecretSpec := swarmtypes.SecretSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: referencedSecretName,
|
||||
},
|
||||
Data: []byte("this is a secret"),
|
||||
}
|
||||
referencedSecret, err := client.SecretCreate(ctx, referencedSecretSpec)
|
||||
assert.Check(t, err)
|
||||
|
||||
referencedConfigName := "referencedconfig_" + t.Name()
|
||||
referencedConfigSpec := swarmtypes.ConfigSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: referencedConfigName,
|
||||
},
|
||||
Data: []byte("this is a config"),
|
||||
}
|
||||
referencedConfig, err := client.ConfigCreate(ctx, referencedConfigSpec)
|
||||
assert.Check(t, err)
|
||||
|
||||
templatedSecretName := "templated_secret_" + t.Name()
|
||||
secretSpec := swarmtypes.SecretSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: templatedSecretName,
|
||||
},
|
||||
Templating: &swarmtypes.Driver{
|
||||
Name: "golang",
|
||||
},
|
||||
Data: []byte("SERVICE_NAME={{.Service.Name}}\n" +
|
||||
"{{secret \"referencedsecrettarget\"}}\n" +
|
||||
"{{config \"referencedconfigtarget\"}}\n"),
|
||||
}
|
||||
|
||||
templatedSecret, err := client.SecretCreate(ctx, secretSpec)
|
||||
assert.Check(t, err)
|
||||
|
||||
serviceName := "svc_" + t.Name()
|
||||
serviceID := swarm.CreateService(t, d,
|
||||
swarm.ServiceWithSecret(
|
||||
&swarmtypes.SecretReference{
|
||||
File: &swarmtypes.SecretReferenceFileTarget{
|
||||
Name: "templated_secret",
|
||||
UID: "0",
|
||||
GID: "0",
|
||||
Mode: 0600,
|
||||
},
|
||||
SecretID: templatedSecret.ID,
|
||||
SecretName: templatedSecretName,
|
||||
},
|
||||
),
|
||||
swarm.ServiceWithConfig(
|
||||
&swarmtypes.ConfigReference{
|
||||
File: &swarmtypes.ConfigReferenceFileTarget{
|
||||
Name: "referencedconfigtarget",
|
||||
UID: "0",
|
||||
GID: "0",
|
||||
Mode: 0600,
|
||||
},
|
||||
ConfigID: referencedConfig.ID,
|
||||
ConfigName: referencedConfigName,
|
||||
},
|
||||
),
|
||||
swarm.ServiceWithSecret(
|
||||
&swarmtypes.SecretReference{
|
||||
File: &swarmtypes.SecretReferenceFileTarget{
|
||||
Name: "referencedsecrettarget",
|
||||
UID: "0",
|
||||
GID: "0",
|
||||
Mode: 0600,
|
||||
},
|
||||
SecretID: referencedSecret.ID,
|
||||
SecretName: referencedSecretName,
|
||||
},
|
||||
),
|
||||
swarm.ServiceWithName(serviceName),
|
||||
)
|
||||
|
||||
var tasks []swarmtypes.Task
|
||||
waitAndAssert(t, 60*time.Second, func(t *testing.T) bool {
|
||||
tasks = swarm.GetRunningTasks(t, d, serviceID)
|
||||
return len(tasks) > 0
|
||||
})
|
||||
|
||||
task := tasks[0]
|
||||
waitAndAssert(t, 60*time.Second, func(t *testing.T) bool {
|
||||
if task.NodeID == "" || (task.Status.ContainerStatus == nil || task.Status.ContainerStatus.ContainerID == "") {
|
||||
task, _, _ = client.TaskInspectWithRaw(context.Background(), task.ID)
|
||||
}
|
||||
return task.NodeID != "" && task.Status.ContainerStatus != nil && task.Status.ContainerStatus.ContainerID != ""
|
||||
})
|
||||
|
||||
attach := swarm.ExecTask(t, d, task, types.ExecConfig{
|
||||
Cmd: []string{"/bin/cat", "/run/secrets/templated_secret"},
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
})
|
||||
|
||||
expect := "SERVICE_NAME=" + serviceName + "\n" +
|
||||
"this is a secret\n" +
|
||||
"this is a config\n"
|
||||
assertAttachedStream(t, attach, expect)
|
||||
|
||||
attach = swarm.ExecTask(t, d, task, types.ExecConfig{
|
||||
Cmd: []string{"mount"},
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
})
|
||||
assertAttachedStream(t, attach, "tmpfs on /run/secrets/templated_secret type tmpfs")
|
||||
}
|
||||
|
||||
func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
_, err := stdcopy.StdCopy(buf, buf, attach.Reader)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(buf.String(), expect))
|
||||
}
|
||||
|
||||
func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool) {
|
||||
t.Helper()
|
||||
after := time.After(timeout)
|
||||
for {
|
||||
select {
|
||||
case <-after:
|
||||
t.Fatalf("timed out waiting for condition")
|
||||
default:
|
||||
}
|
||||
if f(t) {
|
||||
return
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
374
vendor/github.com/docker/docker-ce/components/engine/integration/service/create_test.go
generated
vendored
Normal file
374
vendor/github.com/docker/docker-ce/components/engine/integration/service/create_test.go
generated
vendored
Normal file
|
@ -0,0 +1,374 @@
|
|||
package service // import "github.com/docker/docker/integration/service"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/network"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
)
|
||||
|
||||
func TestServiceCreateInit(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
t.Run("daemonInitDisabled", testServiceCreateInit(false))
|
||||
t.Run("daemonInitEnabled", testServiceCreateInit(true))
|
||||
}
|
||||
|
||||
func testServiceCreateInit(daemonEnabled bool) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
var ops = []func(*daemon.Daemon){}
|
||||
|
||||
if daemonEnabled {
|
||||
ops = append(ops, daemon.WithInit)
|
||||
}
|
||||
d := swarm.NewSwarm(t, testEnv, ops...)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
booleanTrue := true
|
||||
booleanFalse := false
|
||||
|
||||
serviceID := swarm.CreateService(t, d)
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
|
||||
i := inspectServiceContainer(t, client, serviceID)
|
||||
// HostConfig.Init == nil means that it delegates to daemon configuration
|
||||
assert.Check(t, i.HostConfig.Init == nil)
|
||||
|
||||
serviceID = swarm.CreateService(t, d, swarm.ServiceWithInit(&booleanTrue))
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
|
||||
i = inspectServiceContainer(t, client, serviceID)
|
||||
assert.Check(t, is.Equal(true, *i.HostConfig.Init))
|
||||
|
||||
serviceID = swarm.CreateService(t, d, swarm.ServiceWithInit(&booleanFalse))
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
|
||||
i = inspectServiceContainer(t, client, serviceID)
|
||||
assert.Check(t, is.Equal(false, *i.HostConfig.Init))
|
||||
}
|
||||
}
|
||||
|
||||
func inspectServiceContainer(t *testing.T, client client.APIClient, serviceID string) types.ContainerJSON {
|
||||
t.Helper()
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("label", fmt.Sprintf("com.docker.swarm.service.id=%s", serviceID))
|
||||
containers, err := client.ContainerList(context.Background(), types.ContainerListOptions{Filters: filter})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(containers, 1))
|
||||
|
||||
i, err := client.ContainerInspect(context.Background(), containers[0].ID)
|
||||
assert.NilError(t, err)
|
||||
return i
|
||||
}
|
||||
|
||||
func TestCreateServiceMultipleTimes(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
overlayName := "overlay1_" + t.Name()
|
||||
overlayID := network.CreateNoError(t, context.Background(), client, overlayName,
|
||||
network.WithCheckDuplicate(),
|
||||
network.WithDriver("overlay"),
|
||||
)
|
||||
|
||||
var instances uint64 = 4
|
||||
|
||||
serviceName := "TestService_" + t.Name()
|
||||
serviceSpec := []swarm.ServiceSpecOpt{
|
||||
swarm.ServiceWithReplicas(instances),
|
||||
swarm.ServiceWithName(serviceName),
|
||||
swarm.ServiceWithNetwork(overlayName),
|
||||
}
|
||||
|
||||
serviceID := swarm.CreateService(t, d, serviceSpec...)
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, instances), swarm.ServicePoll)
|
||||
|
||||
_, _, err := client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.ServiceRemove(context.Background(), serviceID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, serviceIsRemoved(client, serviceID), swarm.ServicePoll)
|
||||
poll.WaitOn(t, noTasks(client), swarm.ServicePoll)
|
||||
|
||||
serviceID2 := swarm.CreateService(t, d, serviceSpec...)
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID2, instances), swarm.ServicePoll)
|
||||
|
||||
err = client.ServiceRemove(context.Background(), serviceID2)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, serviceIsRemoved(client, serviceID2), swarm.ServicePoll)
|
||||
poll.WaitOn(t, noTasks(client), swarm.ServicePoll)
|
||||
|
||||
err = client.NetworkRemove(context.Background(), overlayID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, networkIsRemoved(client, overlayID), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
|
||||
}
|
||||
|
||||
func TestCreateWithDuplicateNetworkNames(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
name := "foo_" + t.Name()
|
||||
n1 := network.CreateNoError(t, context.Background(), client, name,
|
||||
network.WithDriver("bridge"),
|
||||
)
|
||||
n2 := network.CreateNoError(t, context.Background(), client, name,
|
||||
network.WithDriver("bridge"),
|
||||
)
|
||||
|
||||
// Dupliates with name but with different driver
|
||||
n3 := network.CreateNoError(t, context.Background(), client, name,
|
||||
network.WithDriver("overlay"),
|
||||
)
|
||||
|
||||
// Create Service with the same name
|
||||
var instances uint64 = 1
|
||||
|
||||
serviceName := "top_" + t.Name()
|
||||
serviceID := swarm.CreateService(t, d,
|
||||
swarm.ServiceWithReplicas(instances),
|
||||
swarm.ServiceWithName(serviceName),
|
||||
swarm.ServiceWithNetwork(name),
|
||||
)
|
||||
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, instances), swarm.ServicePoll)
|
||||
|
||||
resp, _, err := client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(n3, resp.Spec.TaskTemplate.Networks[0].Target))
|
||||
|
||||
// Remove Service
|
||||
err = client.ServiceRemove(context.Background(), serviceID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Make sure task has been destroyed.
|
||||
poll.WaitOn(t, serviceIsRemoved(client, serviceID), swarm.ServicePoll)
|
||||
|
||||
// Remove networks
|
||||
err = client.NetworkRemove(context.Background(), n3)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.NetworkRemove(context.Background(), n2)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.NetworkRemove(context.Background(), n1)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Make sure networks have been destroyed.
|
||||
poll.WaitOn(t, networkIsRemoved(client, n3), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
|
||||
poll.WaitOn(t, networkIsRemoved(client, n2), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
|
||||
poll.WaitOn(t, networkIsRemoved(client, n1), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
|
||||
}
|
||||
|
||||
func TestCreateServiceSecretFileMode(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
secretName := "TestSecret_" + t.Name()
|
||||
secretResp, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: secretName,
|
||||
},
|
||||
Data: []byte("TESTSECRET"),
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
var instances uint64 = 1
|
||||
serviceName := "TestService_" + t.Name()
|
||||
serviceID := swarm.CreateService(t, d,
|
||||
swarm.ServiceWithReplicas(instances),
|
||||
swarm.ServiceWithName(serviceName),
|
||||
swarm.ServiceWithCommand([]string{"/bin/sh", "-c", "ls -l /etc/secret || /bin/top"}),
|
||||
swarm.ServiceWithSecret(&swarmtypes.SecretReference{
|
||||
File: &swarmtypes.SecretReferenceFileTarget{
|
||||
Name: "/etc/secret",
|
||||
UID: "0",
|
||||
GID: "0",
|
||||
Mode: 0777,
|
||||
},
|
||||
SecretID: secretResp.ID,
|
||||
SecretName: secretName,
|
||||
}),
|
||||
)
|
||||
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, instances), swarm.ServicePoll)
|
||||
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("service", serviceID)
|
||||
tasks, err := client.TaskList(ctx, types.TaskListOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(len(tasks), 1))
|
||||
|
||||
body, err := client.ContainerLogs(ctx, tasks[0].Status.ContainerStatus.ContainerID, types.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
defer body.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(body)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(string(content), "-rwxrwxrwx"))
|
||||
|
||||
err = client.ServiceRemove(ctx, serviceID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, serviceIsRemoved(client, serviceID), swarm.ServicePoll)
|
||||
poll.WaitOn(t, noTasks(client), swarm.ServicePoll)
|
||||
|
||||
err = client.SecretRemove(ctx, secretName)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestCreateServiceConfigFileMode(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
configName := "TestConfig_" + t.Name()
|
||||
configResp, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: configName,
|
||||
},
|
||||
Data: []byte("TESTCONFIG"),
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
var instances uint64 = 1
|
||||
serviceName := "TestService_" + t.Name()
|
||||
serviceID := swarm.CreateService(t, d,
|
||||
swarm.ServiceWithName(serviceName),
|
||||
swarm.ServiceWithCommand([]string{"/bin/sh", "-c", "ls -l /etc/config || /bin/top"}),
|
||||
swarm.ServiceWithReplicas(instances),
|
||||
swarm.ServiceWithConfig(&swarmtypes.ConfigReference{
|
||||
File: &swarmtypes.ConfigReferenceFileTarget{
|
||||
Name: "/etc/config",
|
||||
UID: "0",
|
||||
GID: "0",
|
||||
Mode: 0777,
|
||||
},
|
||||
ConfigID: configResp.ID,
|
||||
ConfigName: configName,
|
||||
}),
|
||||
)
|
||||
|
||||
poll.WaitOn(t, serviceRunningTasksCount(client, serviceID, instances))
|
||||
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("service", serviceID)
|
||||
tasks, err := client.TaskList(ctx, types.TaskListOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(len(tasks), 1))
|
||||
|
||||
body, err := client.ContainerLogs(ctx, tasks[0].Status.ContainerStatus.ContainerID, types.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
defer body.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(body)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(string(content), "-rwxrwxrwx"))
|
||||
|
||||
err = client.ServiceRemove(ctx, serviceID)
|
||||
assert.NilError(t, err)
|
||||
|
||||
poll.WaitOn(t, serviceIsRemoved(client, serviceID))
|
||||
poll.WaitOn(t, noTasks(client))
|
||||
|
||||
err = client.ConfigRemove(ctx, configName)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func serviceRunningTasksCount(client client.ServiceAPIClient, serviceID string, instances uint64) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("service", serviceID)
|
||||
tasks, err := client.TaskList(context.Background(), types.TaskListOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
switch {
|
||||
case err != nil:
|
||||
return poll.Error(err)
|
||||
case len(tasks) == int(instances):
|
||||
for _, task := range tasks {
|
||||
if task.Status.State != swarmtypes.TaskStateRunning {
|
||||
return poll.Continue("waiting for tasks to enter run state")
|
||||
}
|
||||
}
|
||||
return poll.Success()
|
||||
default:
|
||||
return poll.Continue("task count at %d waiting for %d", len(tasks), instances)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func noTasks(client client.ServiceAPIClient) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
filter := filters.NewArgs()
|
||||
tasks, err := client.TaskList(context.Background(), types.TaskListOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
switch {
|
||||
case err != nil:
|
||||
return poll.Error(err)
|
||||
case len(tasks) == 0:
|
||||
return poll.Success()
|
||||
default:
|
||||
return poll.Continue("task count at %d waiting for 0", len(tasks))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func serviceIsRemoved(client client.ServiceAPIClient, serviceID string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("service", serviceID)
|
||||
_, err := client.TaskList(context.Background(), types.TaskListOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
if err == nil {
|
||||
return poll.Continue("waiting for service %s to be deleted", serviceID)
|
||||
}
|
||||
return poll.Success()
|
||||
}
|
||||
}
|
||||
|
||||
func networkIsRemoved(client client.NetworkAPIClient, networkID string) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
_, err := client.NetworkInspect(context.Background(), networkID, types.NetworkInspectOptions{})
|
||||
if err == nil {
|
||||
return poll.Continue("waiting for network %s to be removed", networkID)
|
||||
}
|
||||
return poll.Success()
|
||||
}
|
||||
}
|
153
vendor/github.com/docker/docker-ce/components/engine/integration/service/inspect_test.go
generated
vendored
Normal file
153
vendor/github.com/docker/docker-ce/components/engine/integration/service/inspect_test.go
generated
vendored
Normal file
|
@ -0,0 +1,153 @@
|
|||
package service // import "github.com/docker/docker/integration/service"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestInspect(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
|
||||
var now = time.Now()
|
||||
var instances uint64 = 2
|
||||
serviceSpec := fullSwarmServiceSpec("test-service-inspect", instances)
|
||||
|
||||
ctx := context.Background()
|
||||
resp, err := client.ServiceCreate(ctx, serviceSpec, types.ServiceCreateOptions{
|
||||
QueryRegistry: false,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
id := resp.ID
|
||||
poll.WaitOn(t, serviceContainerCount(client, id, instances))
|
||||
|
||||
service, _, err := client.ServiceInspectWithRaw(ctx, id, types.ServiceInspectOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
expected := swarmtypes.Service{
|
||||
ID: id,
|
||||
Spec: serviceSpec,
|
||||
Meta: swarmtypes.Meta{
|
||||
Version: swarmtypes.Version{Index: uint64(11)},
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
},
|
||||
}
|
||||
assert.Check(t, is.DeepEqual(service, expected, cmpServiceOpts()))
|
||||
}
|
||||
|
||||
// TODO: use helpers from gotest.tools/assert/opt when available
|
||||
func cmpServiceOpts() cmp.Option {
|
||||
const threshold = 20 * time.Second
|
||||
|
||||
metaTimeFields := func(path cmp.Path) bool {
|
||||
switch path.String() {
|
||||
case "Meta.CreatedAt", "Meta.UpdatedAt":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
withinThreshold := cmp.Comparer(func(x, y time.Time) bool {
|
||||
delta := x.Sub(y)
|
||||
return delta < threshold && delta > -threshold
|
||||
})
|
||||
|
||||
return cmp.FilterPath(metaTimeFields, withinThreshold)
|
||||
}
|
||||
|
||||
func fullSwarmServiceSpec(name string, replicas uint64) swarmtypes.ServiceSpec {
|
||||
restartDelay := 100 * time.Millisecond
|
||||
maxAttempts := uint64(4)
|
||||
|
||||
return swarmtypes.ServiceSpec{
|
||||
Annotations: swarmtypes.Annotations{
|
||||
Name: name,
|
||||
Labels: map[string]string{
|
||||
"service-label": "service-label-value",
|
||||
},
|
||||
},
|
||||
TaskTemplate: swarmtypes.TaskSpec{
|
||||
ContainerSpec: &swarmtypes.ContainerSpec{
|
||||
Image: "busybox:latest",
|
||||
Labels: map[string]string{"container-label": "container-value"},
|
||||
Command: []string{"/bin/top"},
|
||||
Args: []string{"-u", "root"},
|
||||
Hostname: "hostname",
|
||||
Env: []string{"envvar=envvalue"},
|
||||
Dir: "/work",
|
||||
User: "root",
|
||||
StopSignal: "SIGINT",
|
||||
StopGracePeriod: &restartDelay,
|
||||
Hosts: []string{"8.8.8.8 google"},
|
||||
DNSConfig: &swarmtypes.DNSConfig{
|
||||
Nameservers: []string{"8.8.8.8"},
|
||||
Search: []string{"somedomain"},
|
||||
},
|
||||
Isolation: container.IsolationDefault,
|
||||
},
|
||||
RestartPolicy: &swarmtypes.RestartPolicy{
|
||||
Delay: &restartDelay,
|
||||
Condition: swarmtypes.RestartPolicyConditionOnFailure,
|
||||
MaxAttempts: &maxAttempts,
|
||||
},
|
||||
Runtime: swarmtypes.RuntimeContainer,
|
||||
},
|
||||
Mode: swarmtypes.ServiceMode{
|
||||
Replicated: &swarmtypes.ReplicatedService{
|
||||
Replicas: &replicas,
|
||||
},
|
||||
},
|
||||
UpdateConfig: &swarmtypes.UpdateConfig{
|
||||
Parallelism: 2,
|
||||
Delay: 200 * time.Second,
|
||||
FailureAction: swarmtypes.UpdateFailureActionContinue,
|
||||
Monitor: 2 * time.Second,
|
||||
MaxFailureRatio: 0.2,
|
||||
Order: swarmtypes.UpdateOrderStopFirst,
|
||||
},
|
||||
RollbackConfig: &swarmtypes.UpdateConfig{
|
||||
Parallelism: 3,
|
||||
Delay: 300 * time.Second,
|
||||
FailureAction: swarmtypes.UpdateFailureActionPause,
|
||||
Monitor: 3 * time.Second,
|
||||
MaxFailureRatio: 0.3,
|
||||
Order: swarmtypes.UpdateOrderStartFirst,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func serviceContainerCount(client client.ServiceAPIClient, id string, count uint64) func(log poll.LogT) poll.Result {
|
||||
return func(log poll.LogT) poll.Result {
|
||||
filter := filters.NewArgs()
|
||||
filter.Add("service", id)
|
||||
tasks, err := client.TaskList(context.Background(), types.TaskListOptions{
|
||||
Filters: filter,
|
||||
})
|
||||
switch {
|
||||
case err != nil:
|
||||
return poll.Error(err)
|
||||
case len(tasks) == int(count):
|
||||
return poll.Success()
|
||||
default:
|
||||
return poll.Continue("task count at %d waiting for %d", len(tasks), count)
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/service/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/service/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package service // import "github.com/docker/docker/integration/service"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
75
vendor/github.com/docker/docker-ce/components/engine/integration/service/network_test.go
generated
vendored
Normal file
75
vendor/github.com/docker/docker-ce/components/engine/integration/service/network_test.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
package service // import "github.com/docker/docker/integration/service"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
net "github.com/docker/docker/integration/internal/network"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func TestDockerNetworkConnectAlias(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
d := swarm.NewSwarm(t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
|
||||
name := t.Name() + "test-alias"
|
||||
net.CreateNoError(t, ctx, client, name,
|
||||
net.WithDriver("overlay"),
|
||||
net.WithAttachable(),
|
||||
)
|
||||
|
||||
cID1 := container.Create(t, ctx, client, func(c *container.TestContainerConfig) {
|
||||
c.NetworkingConfig = &network.NetworkingConfig{
|
||||
EndpointsConfig: map[string]*network.EndpointSettings{
|
||||
name: {},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
err := client.NetworkConnect(ctx, name, cID1, &network.EndpointSettings{
|
||||
Aliases: []string{
|
||||
"aaa",
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.ContainerStart(ctx, cID1, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
ng1, err := client.ContainerInspect(ctx, cID1)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(len(ng1.NetworkSettings.Networks[name].Aliases), 2))
|
||||
assert.Check(t, is.Equal(ng1.NetworkSettings.Networks[name].Aliases[0], "aaa"))
|
||||
|
||||
cID2 := container.Create(t, ctx, client, func(c *container.TestContainerConfig) {
|
||||
c.NetworkingConfig = &network.NetworkingConfig{
|
||||
EndpointsConfig: map[string]*network.EndpointSettings{
|
||||
name: {},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
err = client.NetworkConnect(ctx, name, cID2, &network.EndpointSettings{
|
||||
Aliases: []string{
|
||||
"bbb",
|
||||
},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.ContainerStart(ctx, cID2, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
ng2, err := client.ContainerInspect(ctx, cID2)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(len(ng2.NetworkSettings.Networks[name].Aliases), 2))
|
||||
assert.Check(t, is.Equal(ng2.NetworkSettings.Networks[name].Aliases[0], "bbb"))
|
||||
}
|
121
vendor/github.com/docker/docker-ce/components/engine/integration/service/plugin_test.go
generated
vendored
Normal file
121
vendor/github.com/docker/docker-ce/components/engine/integration/service/plugin_test.go
generated
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/api/types/swarm/runtime"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/docker/docker/internal/test/fixtures/plugin"
|
||||
"github.com/docker/docker/internal/test/registry"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/poll"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestServicePlugin(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
|
||||
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
||||
skip.If(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64")
|
||||
defer setupTest(t)()
|
||||
|
||||
reg := registry.NewV2(t)
|
||||
defer reg.Close()
|
||||
|
||||
repo := path.Join(registry.DefaultURL, "swarm", "test:v1")
|
||||
repo2 := path.Join(registry.DefaultURL, "swarm", "test:v2")
|
||||
name := "test"
|
||||
|
||||
d := daemon.New(t)
|
||||
d.StartWithBusybox(t)
|
||||
apiclient := d.NewClientT(t)
|
||||
err := plugin.Create(context.Background(), apiclient, repo)
|
||||
assert.NilError(t, err)
|
||||
r, err := apiclient.PluginPush(context.Background(), repo, "")
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(ioutil.Discard, r)
|
||||
assert.NilError(t, err)
|
||||
err = apiclient.PluginRemove(context.Background(), repo, types.PluginRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
err = plugin.Create(context.Background(), apiclient, repo2)
|
||||
assert.NilError(t, err)
|
||||
r, err = apiclient.PluginPush(context.Background(), repo2, "")
|
||||
assert.NilError(t, err)
|
||||
_, err = io.Copy(ioutil.Discard, r)
|
||||
assert.NilError(t, err)
|
||||
err = apiclient.PluginRemove(context.Background(), repo2, types.PluginRemoveOptions{})
|
||||
assert.NilError(t, err)
|
||||
d.Stop(t)
|
||||
|
||||
d1 := swarm.NewSwarm(t, testEnv, daemon.WithExperimental)
|
||||
defer d1.Stop(t)
|
||||
d2 := daemon.New(t, daemon.WithExperimental, daemon.WithSwarmPort(daemon.DefaultSwarmPort+1))
|
||||
d2.StartAndSwarmJoin(t, d1, true)
|
||||
defer d2.Stop(t)
|
||||
d3 := daemon.New(t, daemon.WithExperimental, daemon.WithSwarmPort(daemon.DefaultSwarmPort+2))
|
||||
d3.StartAndSwarmJoin(t, d1, false)
|
||||
defer d3.Stop(t)
|
||||
|
||||
id := d1.CreateService(t, makePlugin(repo, name, nil))
|
||||
poll.WaitOn(t, d1.PluginIsRunning(name), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d2.PluginIsRunning(name), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d3.PluginIsRunning(name), swarm.ServicePoll)
|
||||
|
||||
service := d1.GetService(t, id)
|
||||
d1.UpdateService(t, service, makePlugin(repo2, name, nil))
|
||||
poll.WaitOn(t, d1.PluginReferenceIs(name, repo2), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d2.PluginReferenceIs(name, repo2), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d3.PluginReferenceIs(name, repo2), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d1.PluginIsRunning(name), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d2.PluginIsRunning(name), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d3.PluginIsRunning(name), swarm.ServicePoll)
|
||||
|
||||
d1.RemoveService(t, id)
|
||||
poll.WaitOn(t, d1.PluginIsNotPresent(name), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d2.PluginIsNotPresent(name), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d3.PluginIsNotPresent(name), swarm.ServicePoll)
|
||||
|
||||
// constrain to managers only
|
||||
id = d1.CreateService(t, makePlugin(repo, name, []string{"node.role==manager"}))
|
||||
poll.WaitOn(t, d1.PluginIsRunning(name), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d2.PluginIsRunning(name), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d3.PluginIsNotPresent(name), swarm.ServicePoll)
|
||||
|
||||
d1.RemoveService(t, id)
|
||||
poll.WaitOn(t, d1.PluginIsNotPresent(name), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d2.PluginIsNotPresent(name), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d3.PluginIsNotPresent(name), swarm.ServicePoll)
|
||||
|
||||
// with no name
|
||||
id = d1.CreateService(t, makePlugin(repo, "", nil))
|
||||
poll.WaitOn(t, d1.PluginIsRunning(repo), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d2.PluginIsRunning(repo), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d3.PluginIsRunning(repo), swarm.ServicePoll)
|
||||
|
||||
d1.RemoveService(t, id)
|
||||
poll.WaitOn(t, d1.PluginIsNotPresent(repo), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d2.PluginIsNotPresent(repo), swarm.ServicePoll)
|
||||
poll.WaitOn(t, d3.PluginIsNotPresent(repo), swarm.ServicePoll)
|
||||
}
|
||||
|
||||
func makePlugin(repo, name string, constraints []string) func(*swarmtypes.Service) {
|
||||
return func(s *swarmtypes.Service) {
|
||||
s.Spec.TaskTemplate.Runtime = swarmtypes.RuntimePlugin
|
||||
s.Spec.TaskTemplate.PluginSpec = &runtime.PluginSpec{
|
||||
Name: name,
|
||||
Remote: repo,
|
||||
}
|
||||
if constraints != nil {
|
||||
s.Spec.TaskTemplate.Placement = &swarmtypes.Placement{
|
||||
Constraints: constraints,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/session/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/session/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package session // import "github.com/docker/docker/integration/session"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
48
vendor/github.com/docker/docker-ce/components/engine/integration/session/session_test.go
generated
vendored
Normal file
48
vendor/github.com/docker/docker-ce/components/engine/integration/session/session_test.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
package session // import "github.com/docker/docker/integration/session"
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
req "github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestSessionCreate(t *testing.T) {
|
||||
skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild)
|
||||
|
||||
defer setupTest(t)()
|
||||
|
||||
res, body, err := req.Post("/session", req.With(func(r *http.Request) error {
|
||||
r.Header.Set("X-Docker-Expose-Session-Uuid", "testsessioncreate") // so we don't block default name if something else is using it
|
||||
r.Header.Set("Upgrade", "h2c")
|
||||
return nil
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, body.Close())
|
||||
assert.Check(t, is.DeepEqual(res.StatusCode, http.StatusSwitchingProtocols))
|
||||
assert.Check(t, is.Equal(res.Header.Get("Upgrade"), "h2c"))
|
||||
}
|
||||
|
||||
func TestSessionCreateWithBadUpgrade(t *testing.T) {
|
||||
skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild)
|
||||
|
||||
res, body, err := req.Post("/session")
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(res.StatusCode, http.StatusBadRequest))
|
||||
buf, err := req.ReadBody(body)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(string(buf), "no upgrade"))
|
||||
|
||||
res, body, err = req.Post("/session", req.With(func(r *http.Request) error {
|
||||
r.Header.Set("Upgrade", "foo")
|
||||
return nil
|
||||
}))
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(res.StatusCode, http.StatusBadRequest))
|
||||
buf, err = req.ReadBody(body)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Contains(string(buf), "not supported"))
|
||||
}
|
56
vendor/github.com/docker/docker-ce/components/engine/integration/system/cgroupdriver_systemd_test.go
generated
vendored
Normal file
56
vendor/github.com/docker/docker-ce/components/engine/integration/system/cgroupdriver_systemd_test.go
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
// hasSystemd checks whether the host was booted with systemd as its init
|
||||
// system. Stolen from
|
||||
// https://github.com/coreos/go-systemd/blob/176f85496f4e/util/util.go#L68
|
||||
func hasSystemd() bool {
|
||||
fi, err := os.Lstat("/run/systemd/system")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return fi.IsDir()
|
||||
}
|
||||
|
||||
// TestCgroupDriverSystemdMemoryLimit checks that container
|
||||
// memory limit can be set when using systemd cgroupdriver.
|
||||
// https://github.com/moby/moby/issues/35123
|
||||
func TestCgroupDriverSystemdMemoryLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if !hasSystemd() {
|
||||
t.Skip("systemd not available")
|
||||
}
|
||||
|
||||
d := daemon.New(t)
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
d.StartWithBusybox(t, "--exec-opt", "native.cgroupdriver=systemd", "--iptables=false")
|
||||
defer d.Stop(t)
|
||||
|
||||
const mem = 64 * 1024 * 1024 // 64 MB
|
||||
|
||||
ctx := context.Background()
|
||||
ctrID := container.Create(t, ctx, client, func(c *container.TestContainerConfig) {
|
||||
c.HostConfig.Resources.Memory = mem
|
||||
})
|
||||
defer client.ContainerRemove(ctx, ctrID, types.ContainerRemoveOptions{Force: true})
|
||||
|
||||
err = client.ContainerStart(ctx, ctrID, types.ContainerStartOptions{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
s, err := client.ContainerInspect(ctx, ctrID)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, s.HostConfig.Memory, mem)
|
||||
}
|
122
vendor/github.com/docker/docker-ce/components/engine/integration/system/event_test.go
generated
vendored
Normal file
122
vendor/github.com/docker/docker-ce/components/engine/integration/system/event_test.go
generated
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
package system // import "github.com/docker/docker/integration/system"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
req "github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestEventsExecDie(t *testing.T) {
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.36"), "broken in earlier versions")
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
cID := container.Run(t, ctx, client)
|
||||
|
||||
id, err := client.ContainerExecCreate(ctx, cID,
|
||||
types.ExecConfig{
|
||||
Cmd: strslice.StrSlice([]string{"echo", "hello"}),
|
||||
},
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
filters := filters.NewArgs(
|
||||
filters.Arg("container", cID),
|
||||
filters.Arg("event", "exec_die"),
|
||||
)
|
||||
msg, errors := client.Events(ctx, types.EventsOptions{
|
||||
Filters: filters,
|
||||
})
|
||||
|
||||
err = client.ContainerExecStart(ctx, id.ID,
|
||||
types.ExecStartCheck{
|
||||
Detach: true,
|
||||
Tty: false,
|
||||
},
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
select {
|
||||
case m := <-msg:
|
||||
assert.Equal(t, m.Type, "container")
|
||||
assert.Equal(t, m.Actor.ID, cID)
|
||||
assert.Equal(t, m.Action, "exec_die")
|
||||
assert.Equal(t, m.Actor.Attributes["execID"], id.ID)
|
||||
assert.Equal(t, m.Actor.Attributes["exitCode"], "0")
|
||||
case err = <-errors:
|
||||
t.Fatal(err)
|
||||
case <-time.After(time.Second * 3):
|
||||
t.Fatal("timeout hit")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Test case for #18888: Events messages have been switched from generic
|
||||
// `JSONMessage` to `events.Message` types. The switch does not break the
|
||||
// backward compatibility so old `JSONMessage` could still be used.
|
||||
// This test verifies that backward compatibility maintains.
|
||||
func TestEventsBackwardsCompatible(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
ctx := context.Background()
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
since := request.DaemonTime(ctx, t, client, testEnv)
|
||||
ts := strconv.FormatInt(since.Unix(), 10)
|
||||
|
||||
cID := container.Create(t, ctx, client)
|
||||
|
||||
// In case there is no events, the API should have responded immediately (not blocking),
|
||||
// The test here makes sure the response time is less than 3 sec.
|
||||
expectedTime := time.Now().Add(3 * time.Second)
|
||||
emptyResp, emptyBody, err := req.Get("/events")
|
||||
assert.NilError(t, err)
|
||||
defer emptyBody.Close()
|
||||
assert.Check(t, is.DeepEqual(http.StatusOK, emptyResp.StatusCode))
|
||||
assert.Check(t, time.Now().Before(expectedTime), "timeout waiting for events api to respond, should have responded immediately")
|
||||
|
||||
// We also test to make sure the `events.Message` is compatible with `JSONMessage`
|
||||
q := url.Values{}
|
||||
q.Set("since", ts)
|
||||
_, body, err := req.Get("/events?" + q.Encode())
|
||||
assert.NilError(t, err)
|
||||
defer body.Close()
|
||||
|
||||
dec := json.NewDecoder(body)
|
||||
var containerCreateEvent *jsonmessage.JSONMessage
|
||||
for {
|
||||
var event jsonmessage.JSONMessage
|
||||
if err := dec.Decode(&event); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
if event.Status == "create" && event.ID == cID {
|
||||
containerCreateEvent = &event
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert.Check(t, containerCreateEvent != nil)
|
||||
assert.Check(t, is.Equal("create", containerCreateEvent.Status))
|
||||
assert.Check(t, is.Equal(cID, containerCreateEvent.ID))
|
||||
assert.Check(t, is.Equal("busybox", containerCreateEvent.From))
|
||||
}
|
48
vendor/github.com/docker/docker-ce/components/engine/integration/system/info_linux_test.go
generated
vendored
Normal file
48
vendor/github.com/docker/docker-ce/components/engine/integration/system/info_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
// +build !windows
|
||||
|
||||
package system // import "github.com/docker/docker/integration/system"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
req "github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func TestInfoBinaryCommits(t *testing.T) {
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
info, err := client.Info(context.Background())
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, "N/A" != info.ContainerdCommit.ID)
|
||||
assert.Check(t, is.Equal(testEnv.DaemonInfo.ContainerdCommit.Expected, info.ContainerdCommit.Expected))
|
||||
assert.Check(t, is.Equal(info.ContainerdCommit.Expected, info.ContainerdCommit.ID))
|
||||
|
||||
assert.Check(t, "N/A" != info.InitCommit.ID)
|
||||
assert.Check(t, is.Equal(testEnv.DaemonInfo.InitCommit.Expected, info.InitCommit.Expected))
|
||||
assert.Check(t, is.Equal(info.InitCommit.Expected, info.InitCommit.ID))
|
||||
|
||||
assert.Check(t, "N/A" != info.RuncCommit.ID)
|
||||
assert.Check(t, is.Equal(testEnv.DaemonInfo.RuncCommit.Expected, info.RuncCommit.Expected))
|
||||
assert.Check(t, is.Equal(info.RuncCommit.Expected, info.RuncCommit.ID))
|
||||
}
|
||||
|
||||
func TestInfoAPIVersioned(t *testing.T) {
|
||||
// Windows only supports 1.25 or later
|
||||
|
||||
res, body, err := req.Get("/v1.20/info")
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(res.StatusCode, http.StatusOK))
|
||||
|
||||
b, err := req.ReadBody(body)
|
||||
assert.NilError(t, err)
|
||||
|
||||
out := string(b)
|
||||
assert.Check(t, is.Contains(out, "ExecutionDriver"))
|
||||
assert.Check(t, is.Contains(out, "not supported"))
|
||||
}
|
66
vendor/github.com/docker/docker-ce/components/engine/integration/system/info_test.go
generated
vendored
Normal file
66
vendor/github.com/docker/docker-ce/components/engine/integration/system/info_test.go
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
package system // import "github.com/docker/docker/integration/system"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func TestInfoAPI(t *testing.T) {
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
info, err := client.Info(context.Background())
|
||||
assert.NilError(t, err)
|
||||
|
||||
// always shown fields
|
||||
stringsToCheck := []string{
|
||||
"ID",
|
||||
"Containers",
|
||||
"ContainersRunning",
|
||||
"ContainersPaused",
|
||||
"ContainersStopped",
|
||||
"Images",
|
||||
"LoggingDriver",
|
||||
"OperatingSystem",
|
||||
"NCPU",
|
||||
"OSType",
|
||||
"Architecture",
|
||||
"MemTotal",
|
||||
"KernelVersion",
|
||||
"Driver",
|
||||
"ServerVersion",
|
||||
"SecurityOptions"}
|
||||
|
||||
out := fmt.Sprintf("%+v", info)
|
||||
for _, linePrefix := range stringsToCheck {
|
||||
assert.Check(t, is.Contains(out, linePrefix))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInfoAPIWarnings(t *testing.T) {
|
||||
d := daemon.New(t)
|
||||
|
||||
client, err := d.NewClient()
|
||||
assert.NilError(t, err)
|
||||
|
||||
d.StartWithBusybox(t, "--iptables=false", "-H=0.0.0.0:23756", "-H=unix://"+d.Sock())
|
||||
defer d.Stop(t)
|
||||
|
||||
info, err := client.Info(context.Background())
|
||||
assert.NilError(t, err)
|
||||
|
||||
stringsToCheck := []string{
|
||||
"Access to the remote API is equivalent to root access",
|
||||
"http://0.0.0.0:23756",
|
||||
}
|
||||
|
||||
out := fmt.Sprintf("%+v", info)
|
||||
for _, linePrefix := range stringsToCheck {
|
||||
assert.Check(t, is.Contains(out, linePrefix))
|
||||
}
|
||||
}
|
28
vendor/github.com/docker/docker-ce/components/engine/integration/system/login_test.go
generated
vendored
Normal file
28
vendor/github.com/docker/docker-ce/components/engine/integration/system/login_test.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
package system // import "github.com/docker/docker/integration/system"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/requirement"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
// Test case for GitHub 22244
|
||||
func TestLoginFailsWithBadCredentials(t *testing.T) {
|
||||
skip.If(t, !requirement.HasHubConnectivity(t))
|
||||
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
config := types.AuthConfig{
|
||||
Username: "no-user",
|
||||
Password: "no-password",
|
||||
}
|
||||
_, err := client.RegistryLogin(context.Background(), config)
|
||||
expected := "Error response from daemon: Get https://registry-1.docker.io/v2/: unauthorized: incorrect username or password"
|
||||
assert.Check(t, is.Error(err, expected))
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/system/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/system/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package system // import "github.com/docker/docker/integration/system"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
23
vendor/github.com/docker/docker-ce/components/engine/integration/system/version_test.go
generated
vendored
Normal file
23
vendor/github.com/docker/docker-ce/components/engine/integration/system/version_test.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
package system // import "github.com/docker/docker/integration/system"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
client := request.NewAPIClient(t)
|
||||
|
||||
version, err := client.ServerVersion(context.Background())
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, version.APIVersion != "")
|
||||
assert.Check(t, version.Version != "")
|
||||
assert.Check(t, version.MinAPIVersion != "")
|
||||
assert.Check(t, is.Equal(testEnv.DaemonInfo.ExperimentalBuild, version.Experimental))
|
||||
assert.Check(t, is.Equal(testEnv.OSType, version.Os))
|
||||
}
|
23
vendor/github.com/docker/docker-ce/components/engine/integration/testdata/https/ca.pem
generated
vendored
Normal file
23
vendor/github.com/docker/docker-ce/components/engine/integration/testdata/https/ca.pem
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIID0TCCAzqgAwIBAgIJAP2r7GqEJwSnMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
|
||||
VQQGEwJVUzELMAkGA1UECBMCQ0ExFTATBgNVBAcTDFNhbkZyYW5jaXNjbzEVMBMG
|
||||
A1UEChMMRm9ydC1GdW5zdG9uMREwDwYDVQQLEwhjaGFuZ2VtZTERMA8GA1UEAxMI
|
||||
Y2hhbmdlbWUxETAPBgNVBCkTCGNoYW5nZW1lMR8wHQYJKoZIhvcNAQkBFhBtYWls
|
||||
QGhvc3QuZG9tYWluMB4XDTEzMTIwMzE2NTYzMFoXDTIzMTIwMTE2NTYzMFowgaIx
|
||||
CzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEVMBMGA1UEBxMMU2FuRnJhbmNpc2Nv
|
||||
MRUwEwYDVQQKEwxGb3J0LUZ1bnN0b24xETAPBgNVBAsTCGNoYW5nZW1lMREwDwYD
|
||||
VQQDEwhjaGFuZ2VtZTERMA8GA1UEKRMIY2hhbmdlbWUxHzAdBgkqhkiG9w0BCQEW
|
||||
EG1haWxAaG9zdC5kb21haW4wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALAn
|
||||
0xDw+5y7ZptQacq66pUhRu82JP2WU6IDgo5QUtNU6/CX5PwQATe/OnYTZQFbksxp
|
||||
AU9boG0FCkgxfsgPYXEuZxVEGKI2fxfKHOZZI8mrkWmj6eWU/0cvCjGVc9rTITP5
|
||||
sNQvg+hORyVDdNp2IdsbMJayiB3AQYMFx3vSDOMTAgMBAAGjggELMIIBBzAdBgNV
|
||||
HQ4EFgQUZu7DFz09q0QBa2+ymRm9qgK1NPswgdcGA1UdIwSBzzCBzIAUZu7DFz09
|
||||
q0QBa2+ymRm9qgK1NPuhgaikgaUwgaIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJD
|
||||
QTEVMBMGA1UEBxMMU2FuRnJhbmNpc2NvMRUwEwYDVQQKEwxGb3J0LUZ1bnN0b24x
|
||||
ETAPBgNVBAsTCGNoYW5nZW1lMREwDwYDVQQDEwhjaGFuZ2VtZTERMA8GA1UEKRMI
|
||||
Y2hhbmdlbWUxHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW6CCQD9q+xq
|
||||
hCcEpzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAF8fJKKM+/oOdnNi
|
||||
zEd0M1+PmZOyqvjYQn/2ZR8UHH6Imgc/OPQKZXf0bVE1Txc/DaUNn9Isd1SuCuaE
|
||||
ic3vAIYYU7PmgeNN6vwec48V96T7jr+GAi6AVMhQEc2hHCfVtx11Xx+x6aHDZzJt
|
||||
Zxtf5lL6KSO9Y+EFwM+rju6hm5hW
|
||||
-----END CERTIFICATE-----
|
73
vendor/github.com/docker/docker-ce/components/engine/integration/testdata/https/client-cert.pem
generated
vendored
Normal file
73
vendor/github.com/docker/docker-ce/components/engine/integration/testdata/https/client-cert.pem
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 3 (0x3)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: C=US, ST=CA, L=SanFrancisco, O=Fort-Funston, OU=changeme, CN=changeme/name=changeme/emailAddress=mail@host.domain
|
||||
Validity
|
||||
Not Before: Dec 4 14:17:54 2013 GMT
|
||||
Not After : Dec 2 14:17:54 2023 GMT
|
||||
Subject: C=US, ST=CA, L=SanFrancisco, O=Fort-Funston, OU=changeme, CN=client/name=changeme/emailAddress=mail@host.domain
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (1024 bit)
|
||||
Modulus:
|
||||
00:ca:c9:05:d0:09:4e:3e:a4:fc:d5:14:f4:a5:e8:
|
||||
34:d3:6b:51:e3:f3:62:ea:a1:f0:e8:ed:c4:2a:bc:
|
||||
f0:4f:ca:07:df:e3:88:fa:f4:21:99:35:0e:3d:ea:
|
||||
b0:86:e7:c4:d2:8a:83:2b:42:b8:ec:a3:99:62:70:
|
||||
81:46:cc:fc:a5:1d:d2:63:e8:eb:07:25:9a:e2:25:
|
||||
6d:11:56:f2:1a:51:a1:b6:3e:1c:57:32:e9:7b:2c:
|
||||
aa:1b:cc:97:2d:89:2d:b1:c9:5e:35:28:4d:7c:fa:
|
||||
65:31:3e:f7:70:dd:6e:0b:3c:58:af:a8:2e:24:c0:
|
||||
7e:4e:78:7d:0a:9e:8f:42:43
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
Netscape Comment:
|
||||
Easy-RSA Generated Certificate
|
||||
X509v3 Subject Key Identifier:
|
||||
DE:42:EF:2D:98:A3:6C:A8:AA:E0:8C:71:2C:9D:64:23:A9:E2:7E:81
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:66:EE:C3:17:3D:3D:AB:44:01:6B:6F:B2:99:19:BD:AA:02:B5:34:FB
|
||||
DirName:/C=US/ST=CA/L=SanFrancisco/O=Fort-Funston/OU=changeme/CN=changeme/name=changeme/emailAddress=mail@host.domain
|
||||
serial:FD:AB:EC:6A:84:27:04:A7
|
||||
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Client Authentication
|
||||
X509v3 Key Usage:
|
||||
Digital Signature
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
1c:44:26:ea:e1:66:25:cb:e4:8e:57:1c:f6:b9:17:22:62:40:
|
||||
12:90:8f:3b:b2:61:7a:54:94:8f:b1:20:0b:bf:a3:51:e3:fa:
|
||||
1c:a1:be:92:3a:d0:76:44:c0:57:83:ab:6a:e4:1a:45:49:a4:
|
||||
af:39:0d:60:32:fc:3a:be:d7:fb:5d:99:7a:1f:87:e7:d5:ab:
|
||||
84:a2:5e:90:d8:bf:fa:89:6d:32:26:02:5e:31:35:68:7f:31:
|
||||
f5:6b:51:46:bc:af:70:ed:5a:09:7d:ec:b2:48:4f:fe:c5:2f:
|
||||
56:04:ad:f6:c1:d2:2a:e4:6a:c4:87:fe:08:35:c5:38:cb:5e:
|
||||
4a:c4
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEFTCCA36gAwIBAgIBAzANBgkqhkiG9w0BAQUFADCBojELMAkGA1UEBhMCVVMx
|
||||
CzAJBgNVBAgTAkNBMRUwEwYDVQQHEwxTYW5GcmFuY2lzY28xFTATBgNVBAoTDEZv
|
||||
cnQtRnVuc3RvbjERMA8GA1UECxMIY2hhbmdlbWUxETAPBgNVBAMTCGNoYW5nZW1l
|
||||
MREwDwYDVQQpEwhjaGFuZ2VtZTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0LmRv
|
||||
bWFpbjAeFw0xMzEyMDQxNDE3NTRaFw0yMzEyMDIxNDE3NTRaMIGgMQswCQYDVQQG
|
||||
EwJVUzELMAkGA1UECBMCQ0ExFTATBgNVBAcTDFNhbkZyYW5jaXNjbzEVMBMGA1UE
|
||||
ChMMRm9ydC1GdW5zdG9uMREwDwYDVQQLEwhjaGFuZ2VtZTEPMA0GA1UEAxMGY2xp
|
||||
ZW50MREwDwYDVQQpEwhjaGFuZ2VtZTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0
|
||||
LmRvbWFpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyskF0AlOPqT81RT0
|
||||
peg002tR4/Ni6qHw6O3EKrzwT8oH3+OI+vQhmTUOPeqwhufE0oqDK0K47KOZYnCB
|
||||
Rsz8pR3SY+jrByWa4iVtEVbyGlGhtj4cVzLpeyyqG8yXLYktscleNShNfPplMT73
|
||||
cN1uCzxYr6guJMB+Tnh9Cp6PQkMCAwEAAaOCAVkwggFVMAkGA1UdEwQCMAAwLQYJ
|
||||
YIZIAYb4QgENBCAWHkVhc3ktUlNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV
|
||||
HQ4EFgQU3kLvLZijbKiq4IxxLJ1kI6nifoEwgdcGA1UdIwSBzzCBzIAUZu7DFz09
|
||||
q0QBa2+ymRm9qgK1NPuhgaikgaUwgaIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJD
|
||||
QTEVMBMGA1UEBxMMU2FuRnJhbmNpc2NvMRUwEwYDVQQKEwxGb3J0LUZ1bnN0b24x
|
||||
ETAPBgNVBAsTCGNoYW5nZW1lMREwDwYDVQQDEwhjaGFuZ2VtZTERMA8GA1UEKRMI
|
||||
Y2hhbmdlbWUxHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW6CCQD9q+xq
|
||||
hCcEpzATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCB4AwDQYJKoZIhvcN
|
||||
AQEFBQADgYEAHEQm6uFmJcvkjlcc9rkXImJAEpCPO7JhelSUj7EgC7+jUeP6HKG+
|
||||
kjrQdkTAV4OrauQaRUmkrzkNYDL8Or7X+12Zeh+H59WrhKJekNi/+oltMiYCXjE1
|
||||
aH8x9WtRRryvcO1aCX3sskhP/sUvVgSt9sHSKuRqxIf+CDXFOMteSsQ=
|
||||
-----END CERTIFICATE-----
|
16
vendor/github.com/docker/docker-ce/components/engine/integration/testdata/https/client-key.pem
generated
vendored
Normal file
16
vendor/github.com/docker/docker-ce/components/engine/integration/testdata/https/client-key.pem
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMrJBdAJTj6k/NUU
|
||||
9KXoNNNrUePzYuqh8OjtxCq88E/KB9/jiPr0IZk1Dj3qsIbnxNKKgytCuOyjmWJw
|
||||
gUbM/KUd0mPo6wclmuIlbRFW8hpRobY+HFcy6XssqhvMly2JLbHJXjUoTXz6ZTE+
|
||||
93Ddbgs8WK+oLiTAfk54fQqej0JDAgMBAAECgYBOFEzKp2qbMEexe9ofL2N3rDDh
|
||||
xkrl8OijpzkLA6i78BxMFn4dsnZlWUpciMrjhsYAExkiRRSS+QMMJimAq1jzQqc3
|
||||
FAQV2XGYwkd0cUn7iZGvfNnEPysjsfyYQM+m+sT0ATj4BZjVShC6kkSjTdm1leLN
|
||||
OSvcHdcu3Xxg9ufF0QJBAPYdnNt5sIndt2WECePuRVi+uF4mlxTobFY0fjn26yhC
|
||||
4RsnhhD3Vldygo9gvnkwrAZYaALGSPBewes2InxvjA8CQQDS7erKiNXpwoqz5XiU
|
||||
SVEsIIVTdWzBjGbIqMOu/hUwM5FK4j6JTBks0aTGMyh0YV9L1EzM0X79J29JahCe
|
||||
iQKNAkBKNMOGqTpBV0hko1sYDk96YobUXG5RL4L6uvkUIQ7mJMQam+AgXXL7Ctuy
|
||||
v0iu4a38e8tgisiTMP7nHHtpaXihAkAOiN54/lzfMsykANgCP9scE1GcoqbP34Dl
|
||||
qttxH4kOPT9xzY1JoLjLYdbc4YGUI3GRpBt2sajygNkmUey7P+2xAkBBsVCZFvTw
|
||||
qHvOpPS2kX5ml5xoc/QAHK9N7kR+X7XFYx82RTVSqJEK4lPb+aEWn+CjiIewO4Q5
|
||||
ksDFuNxAzbhl
|
||||
-----END PRIVATE KEY-----
|
76
vendor/github.com/docker/docker-ce/components/engine/integration/testdata/https/server-cert.pem
generated
vendored
Normal file
76
vendor/github.com/docker/docker-ce/components/engine/integration/testdata/https/server-cert.pem
generated
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 4 (0x4)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: C=US, ST=CA, L=SanFrancisco, O=Fort-Funston, OU=changeme, CN=changeme/name=changeme/emailAddress=mail@host.domain
|
||||
Validity
|
||||
Not Before: Dec 4 15:01:20 2013 GMT
|
||||
Not After : Dec 2 15:01:20 2023 GMT
|
||||
Subject: C=US, ST=CA, L=SanFrancisco, O=Fort-Funston, OU=changeme, CN=*/name=changeme/emailAddress=mail@host.domain
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (1024 bit)
|
||||
Modulus:
|
||||
00:c1:ff:7d:30:6f:64:4a:b1:92:b1:71:d1:c1:74:
|
||||
e2:1d:db:2d:11:24:e1:00:d4:00:ae:6f:c8:9e:ae:
|
||||
67:b3:4a:bd:f7:e6:9e:57:6d:19:4c:3c:23:94:2d:
|
||||
3d:d6:63:84:d8:fa:76:2b:38:12:c1:ed:20:9d:32:
|
||||
e0:e8:c2:bf:9a:77:70:04:3f:7f:ca:8c:2c:82:d6:
|
||||
3d:25:5c:02:1a:4f:64:93:03:dd:9c:42:97:5e:09:
|
||||
49:af:f0:c2:e1:30:08:0e:21:46:95:d1:13:59:c0:
|
||||
c8:76:be:94:0d:8b:43:67:21:33:b2:08:60:9d:76:
|
||||
a8:05:32:1e:f9:95:09:14:75
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
Netscape Cert Type:
|
||||
SSL Server
|
||||
Netscape Comment:
|
||||
Easy-RSA Generated Server Certificate
|
||||
X509v3 Subject Key Identifier:
|
||||
14:02:FD:FD:DD:13:38:E0:71:EA:D1:BE:C0:0E:89:1A:2D:B6:19:06
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:66:EE:C3:17:3D:3D:AB:44:01:6B:6F:B2:99:19:BD:AA:02:B5:34:FB
|
||||
DirName:/C=US/ST=CA/L=SanFrancisco/O=Fort-Funston/OU=changeme/CN=changeme/name=changeme/emailAddress=mail@host.domain
|
||||
serial:FD:AB:EC:6A:84:27:04:A7
|
||||
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication
|
||||
X509v3 Key Usage:
|
||||
Digital Signature, Key Encipherment
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
40:0f:10:39:c4:b7:0f:0d:2f:bf:d2:16:cc:8e:d3:9a:fb:8b:
|
||||
ce:4b:7b:0d:48:77:ce:f1:fe:d5:8f:ea:b1:71:ed:49:1d:9f:
|
||||
23:3a:16:d4:70:7c:c5:29:bf:e4:90:34:d0:f0:00:24:f4:e4:
|
||||
df:2c:c3:83:01:66:61:c9:a8:ab:29:e7:98:6d:27:89:4a:76:
|
||||
c9:2e:19:8e:fe:6e:d5:f8:99:11:0e:97:67:4b:34:e3:1e:e3:
|
||||
9f:35:00:a5:32:f9:b5:2c:f2:e0:c5:2e:cc:81:bd:18:dd:5c:
|
||||
12:c8:6b:fa:0c:17:74:30:55:f6:6e:20:9a:6c:1e:09:b4:0c:
|
||||
15:42
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEKjCCA5OgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBojELMAkGA1UEBhMCVVMx
|
||||
CzAJBgNVBAgTAkNBMRUwEwYDVQQHEwxTYW5GcmFuY2lzY28xFTATBgNVBAoTDEZv
|
||||
cnQtRnVuc3RvbjERMA8GA1UECxMIY2hhbmdlbWUxETAPBgNVBAMTCGNoYW5nZW1l
|
||||
MREwDwYDVQQpEwhjaGFuZ2VtZTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0LmRv
|
||||
bWFpbjAeFw0xMzEyMDQxNTAxMjBaFw0yMzEyMDIxNTAxMjBaMIGbMQswCQYDVQQG
|
||||
EwJVUzELMAkGA1UECBMCQ0ExFTATBgNVBAcTDFNhbkZyYW5jaXNjbzEVMBMGA1UE
|
||||
ChMMRm9ydC1GdW5zdG9uMREwDwYDVQQLEwhjaGFuZ2VtZTEKMAgGA1UEAxQBKjER
|
||||
MA8GA1UEKRMIY2hhbmdlbWUxHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21h
|
||||
aW4wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMH/fTBvZEqxkrFx0cF04h3b
|
||||
LREk4QDUAK5vyJ6uZ7NKvffmnldtGUw8I5QtPdZjhNj6dis4EsHtIJ0y4OjCv5p3
|
||||
cAQ/f8qMLILWPSVcAhpPZJMD3ZxCl14JSa/wwuEwCA4hRpXRE1nAyHa+lA2LQ2ch
|
||||
M7IIYJ12qAUyHvmVCRR1AgMBAAGjggFzMIIBbzAJBgNVHRMEAjAAMBEGCWCGSAGG
|
||||
+EIBAQQEAwIGQDA0BglghkgBhvhCAQ0EJxYlRWFzeS1SU0EgR2VuZXJhdGVkIFNl
|
||||
cnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUFAL9/d0TOOBx6tG+wA6JGi22GQYw
|
||||
gdcGA1UdIwSBzzCBzIAUZu7DFz09q0QBa2+ymRm9qgK1NPuhgaikgaUwgaIxCzAJ
|
||||
BgNVBAYTAlVTMQswCQYDVQQIEwJDQTEVMBMGA1UEBxMMU2FuRnJhbmNpc2NvMRUw
|
||||
EwYDVQQKEwxGb3J0LUZ1bnN0b24xETAPBgNVBAsTCGNoYW5nZW1lMREwDwYDVQQD
|
||||
EwhjaGFuZ2VtZTERMA8GA1UEKRMIY2hhbmdlbWUxHzAdBgkqhkiG9w0BCQEWEG1h
|
||||
aWxAaG9zdC5kb21haW6CCQD9q+xqhCcEpzATBgNVHSUEDDAKBggrBgEFBQcDATAL
|
||||
BgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQEFBQADgYEAQA8QOcS3Dw0vv9IWzI7TmvuL
|
||||
zkt7DUh3zvH+1Y/qsXHtSR2fIzoW1HB8xSm/5JA00PAAJPTk3yzDgwFmYcmoqynn
|
||||
mG0niUp2yS4Zjv5u1fiZEQ6XZ0s04x7jnzUApTL5tSzy4MUuzIG9GN1cEshr+gwX
|
||||
dDBV9m4gmmweCbQMFUI=
|
||||
-----END CERTIFICATE-----
|
16
vendor/github.com/docker/docker-ce/components/engine/integration/testdata/https/server-key.pem
generated
vendored
Normal file
16
vendor/github.com/docker/docker-ce/components/engine/integration/testdata/https/server-key.pem
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMH/fTBvZEqxkrFx
|
||||
0cF04h3bLREk4QDUAK5vyJ6uZ7NKvffmnldtGUw8I5QtPdZjhNj6dis4EsHtIJ0y
|
||||
4OjCv5p3cAQ/f8qMLILWPSVcAhpPZJMD3ZxCl14JSa/wwuEwCA4hRpXRE1nAyHa+
|
||||
lA2LQ2chM7IIYJ12qAUyHvmVCRR1AgMBAAECgYAmwckb9RUfSwyYgLm8IYLPHiuJ
|
||||
wkllZfVg5Bo7gXJcQnFjZmJ56uTj8xvUjZlODIHM63TSO5ibv6kFXtXKCqZGd2M+
|
||||
wGbhZ0f+2GvKcwMmJERnIQjuoNaYSQLT0tM0VB9Iz0rJlZC+tzPZ+5pPqEumRdsS
|
||||
IzWNXfF42AhcbwAQYQJBAPVXtMYIJc9EZsz86ZcQiMPWUpCX5vnRmtwL8kKyR8D5
|
||||
4KfYeiowyFffSRMMcclwNHq7TgSXN+nIXM9WyzyzwikCQQDKbNA28AgZp9aT54HP
|
||||
WnbeE2pmt+uk/zl/BtxJSoK6H+69Jec+lf7EgL7HgOWYRSNot4uQWu8IhsHLTiUq
|
||||
+0FtAkEAqwlRxRy4/x24bP+D+QRV0/D97j93joFJbE4Hved7jlSlAV4xDGilwlyv
|
||||
HNB4Iu5OJ6Gcaibhm+FKkmD3noHSwQJBAIpu3fokLzX0bS+bDFBU6qO3HXX/47xj
|
||||
+tsfQvkwZrSI8AkU6c8IX0HdVhsz0FBRQAT2ORDQz1XCarfxykNZrwUCQQCGCBIc
|
||||
BBCWzhHlswlGidWJg3HqqO6hPPClEr3B5G87oCsdeYwiO23XT6rUnoJXfJHp6oCW
|
||||
5nCwDu5ZTP+khltg
|
||||
-----END PRIVATE KEY-----
|
33
vendor/github.com/docker/docker-ce/components/engine/integration/volume/main_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration/volume/main_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package volume // import "github.com/docker/docker/integration/volume"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = environment.EnsureFrozenImagesLinux(testEnv)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func setupTest(t *testing.T) func() {
|
||||
environment.ProtectAll(t, testEnv)
|
||||
return func() { testEnv.Clean(t) }
|
||||
}
|
116
vendor/github.com/docker/docker-ce/components/engine/integration/volume/volume_test.go
generated
vendored
Normal file
116
vendor/github.com/docker/docker-ce/components/engine/integration/volume/volume_test.go
generated
vendored
Normal file
|
@ -0,0 +1,116 @@
|
|||
package volume
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
volumetypes "github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"gotest.tools/skip"
|
||||
)
|
||||
|
||||
func TestVolumesCreateAndList(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
name := t.Name()
|
||||
vol, err := client.VolumeCreate(ctx, volumetypes.VolumeCreateBody{
|
||||
Name: name,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
expected := types.Volume{
|
||||
// Ignore timestamp of CreatedAt
|
||||
CreatedAt: vol.CreatedAt,
|
||||
Driver: "local",
|
||||
Scope: "local",
|
||||
Name: name,
|
||||
Mountpoint: fmt.Sprintf("%s/volumes/%s/_data", testEnv.DaemonInfo.DockerRootDir, name),
|
||||
}
|
||||
assert.Check(t, is.DeepEqual(vol, expected, cmpopts.EquateEmpty()))
|
||||
|
||||
volumes, err := client.VolumeList(ctx, filters.Args{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Check(t, is.Equal(len(volumes.Volumes), 1))
|
||||
assert.Check(t, volumes.Volumes[0] != nil)
|
||||
assert.Check(t, is.DeepEqual(*volumes.Volumes[0], expected, cmpopts.EquateEmpty()))
|
||||
}
|
||||
|
||||
func TestVolumesRemove(t *testing.T) {
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
id := container.Create(t, ctx, client, container.WithVolume(prefix+slash+"foo"))
|
||||
|
||||
c, err := client.ContainerInspect(ctx, id)
|
||||
assert.NilError(t, err)
|
||||
vname := c.Mounts[0].Name
|
||||
|
||||
err = client.VolumeRemove(ctx, vname, false)
|
||||
assert.Check(t, is.ErrorContains(err, "volume is in use"))
|
||||
|
||||
err = client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{
|
||||
Force: true,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.VolumeRemove(ctx, vname, false)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestVolumesInspect(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
|
||||
defer setupTest(t)()
|
||||
client := request.NewAPIClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
// sampling current time minus a minute so to now have false positive in case of delays
|
||||
now := time.Now().Truncate(time.Minute)
|
||||
|
||||
name := t.Name()
|
||||
_, err := client.VolumeCreate(ctx, volumetypes.VolumeCreateBody{
|
||||
Name: name,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
vol, err := client.VolumeInspect(ctx, name)
|
||||
assert.NilError(t, err)
|
||||
|
||||
expected := types.Volume{
|
||||
// Ignore timestamp of CreatedAt
|
||||
CreatedAt: vol.CreatedAt,
|
||||
Driver: "local",
|
||||
Scope: "local",
|
||||
Name: name,
|
||||
Mountpoint: fmt.Sprintf("%s/volumes/%s/_data", testEnv.DaemonInfo.DockerRootDir, name),
|
||||
}
|
||||
assert.Check(t, is.DeepEqual(vol, expected, cmpopts.EquateEmpty()))
|
||||
|
||||
// comparing CreatedAt field time for the new volume to now. Removing a minute from both to avoid false positive
|
||||
testCreatedAt, err := time.Parse(time.RFC3339, strings.TrimSpace(vol.CreatedAt))
|
||||
assert.NilError(t, err)
|
||||
testCreatedAt = testCreatedAt.Truncate(time.Minute)
|
||||
assert.Check(t, is.Equal(testCreatedAt.Equal(now), true), "Time Volume is CreatedAt not equal to current time")
|
||||
}
|
||||
|
||||
func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) {
|
||||
if testEnv.OSType == "windows" {
|
||||
return "c:", `\`
|
||||
}
|
||||
return "", "/"
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue