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
95
vendor/github.com/docker/docker-ce/components/engine/integration-cli/benchmark_test.go
generated
vendored
Normal file
95
vendor/github.com/docker/docker-ce/components/engine/integration-cli/benchmark_test.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) BenchmarkConcurrentContainerActions(c *check.C) {
|
||||
maxConcurrency := runtime.GOMAXPROCS(0)
|
||||
numIterations := c.N
|
||||
outerGroup := &sync.WaitGroup{}
|
||||
outerGroup.Add(maxConcurrency)
|
||||
chErr := make(chan error, numIterations*2*maxConcurrency)
|
||||
|
||||
for i := 0; i < maxConcurrency; i++ {
|
||||
go func() {
|
||||
defer outerGroup.Done()
|
||||
innerGroup := &sync.WaitGroup{}
|
||||
innerGroup.Add(2)
|
||||
|
||||
go func() {
|
||||
defer innerGroup.Done()
|
||||
for i := 0; i < numIterations; i++ {
|
||||
args := []string{"run", "-d", defaultSleepImage}
|
||||
args = append(args, sleepCommandForDaemonPlatform()...)
|
||||
out, _, err := dockerCmdWithError(args...)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
return
|
||||
}
|
||||
|
||||
id := strings.TrimSpace(out)
|
||||
tmpDir, err := ioutil.TempDir("", "docker-concurrent-test-"+id)
|
||||
if err != nil {
|
||||
chErr <- err
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
out, _, err = dockerCmdWithError("cp", id+":/tmp", tmpDir)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
return
|
||||
}
|
||||
|
||||
out, _, err = dockerCmdWithError("kill", id)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
}
|
||||
|
||||
out, _, err = dockerCmdWithError("start", id)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
}
|
||||
|
||||
out, _, err = dockerCmdWithError("kill", id)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
}
|
||||
|
||||
// don't do an rm -f here since it can potentially ignore errors from the graphdriver
|
||||
out, _, err = dockerCmdWithError("rm", id)
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer innerGroup.Done()
|
||||
for i := 0; i < numIterations; i++ {
|
||||
out, _, err := dockerCmdWithError("ps")
|
||||
if err != nil {
|
||||
chErr <- fmt.Errorf(out)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
innerGroup.Wait()
|
||||
}()
|
||||
}
|
||||
|
||||
outerGroup.Wait()
|
||||
close(chErr)
|
||||
|
||||
for err := range chErr {
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
}
|
409
vendor/github.com/docker/docker-ce/components/engine/integration-cli/check_test.go
generated
vendored
Normal file
409
vendor/github.com/docker/docker-ce/components/engine/integration-cli/check_test.go
generated
vendored
Normal file
|
@ -0,0 +1,409 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/docker/docker/integration-cli/environment"
|
||||
testdaemon "github.com/docker/docker/internal/test/daemon"
|
||||
ienv "github.com/docker/docker/internal/test/environment"
|
||||
"github.com/docker/docker/internal/test/fakestorage"
|
||||
"github.com/docker/docker/internal/test/fixtures/plugin"
|
||||
"github.com/docker/docker/internal/test/registry"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
const (
|
||||
// the private registry to use for tests
|
||||
privateRegistryURL = registry.DefaultURL
|
||||
|
||||
// path to containerd's ctr binary
|
||||
ctrBinary = "docker-containerd-ctr"
|
||||
|
||||
// the docker daemon binary to use
|
||||
dockerdBinary = "dockerd"
|
||||
)
|
||||
|
||||
var (
|
||||
testEnv *environment.Execution
|
||||
|
||||
// the docker client binary to use
|
||||
dockerBinary = ""
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
|
||||
reexec.Init() // This is required for external graphdriver tests
|
||||
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
dockerBinary = testEnv.DockerBinary()
|
||||
err := ienv.EnsureFrozenImagesLinux(&testEnv.Execution)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
testEnv.Print()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {
|
||||
cli.SetTestEnvironment(testEnv)
|
||||
fakestorage.SetTestEnvironment(&testEnv.Execution)
|
||||
ienv.ProtectAll(t, &testEnv.Execution)
|
||||
check.TestingT(t)
|
||||
}
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerSuite{})
|
||||
}
|
||||
|
||||
type DockerSuite struct {
|
||||
}
|
||||
|
||||
func (s *DockerSuite) OnTimeout(c *check.C) {
|
||||
if testEnv.IsRemoteDaemon() {
|
||||
return
|
||||
}
|
||||
path := filepath.Join(os.Getenv("DEST"), "docker.pid")
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
c.Fatalf("Failed to get daemon PID from %s\n", path)
|
||||
}
|
||||
|
||||
rawPid, err := strconv.ParseInt(string(b), 10, 32)
|
||||
if err != nil {
|
||||
c.Fatalf("Failed to parse pid from %s: %s\n", path, err)
|
||||
}
|
||||
|
||||
daemonPid := int(rawPid)
|
||||
if daemonPid > 0 {
|
||||
testdaemon.SignalDaemonDump(daemonPid)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TearDownTest(c *check.C) {
|
||||
testEnv.Clean(c)
|
||||
}
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerRegistrySuite{
|
||||
ds: &DockerSuite{},
|
||||
})
|
||||
}
|
||||
|
||||
type DockerRegistrySuite struct {
|
||||
ds *DockerSuite
|
||||
reg *registry.V2
|
||||
d *daemon.Daemon
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) OnTimeout(c *check.C) {
|
||||
s.d.DumpStackAndQuit()
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) SetUpTest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, RegistryHosting, SameHostDaemon)
|
||||
s.reg = registry.NewV2(c)
|
||||
s.reg.WaitReady(c)
|
||||
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TearDownTest(c *check.C) {
|
||||
if s.reg != nil {
|
||||
s.reg.Close()
|
||||
}
|
||||
if s.d != nil {
|
||||
s.d.Stop(c)
|
||||
}
|
||||
s.ds.TearDownTest(c)
|
||||
}
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerSchema1RegistrySuite{
|
||||
ds: &DockerSuite{},
|
||||
})
|
||||
}
|
||||
|
||||
type DockerSchema1RegistrySuite struct {
|
||||
ds *DockerSuite
|
||||
reg *registry.V2
|
||||
d *daemon.Daemon
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) OnTimeout(c *check.C) {
|
||||
s.d.DumpStackAndQuit()
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) SetUpTest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, RegistryHosting, NotArm64, SameHostDaemon)
|
||||
s.reg = registry.NewV2(c, registry.Schema1)
|
||||
s.reg.WaitReady(c)
|
||||
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TearDownTest(c *check.C) {
|
||||
if s.reg != nil {
|
||||
s.reg.Close()
|
||||
}
|
||||
if s.d != nil {
|
||||
s.d.Stop(c)
|
||||
}
|
||||
s.ds.TearDownTest(c)
|
||||
}
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerRegistryAuthHtpasswdSuite{
|
||||
ds: &DockerSuite{},
|
||||
})
|
||||
}
|
||||
|
||||
type DockerRegistryAuthHtpasswdSuite struct {
|
||||
ds *DockerSuite
|
||||
reg *registry.V2
|
||||
d *daemon.Daemon
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthHtpasswdSuite) OnTimeout(c *check.C) {
|
||||
s.d.DumpStackAndQuit()
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthHtpasswdSuite) SetUpTest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, RegistryHosting, SameHostDaemon)
|
||||
s.reg = registry.NewV2(c, registry.Htpasswd)
|
||||
s.reg.WaitReady(c)
|
||||
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthHtpasswdSuite) TearDownTest(c *check.C) {
|
||||
if s.reg != nil {
|
||||
out, err := s.d.Cmd("logout", privateRegistryURL)
|
||||
c.Assert(err, check.IsNil, check.Commentf("%s", out))
|
||||
s.reg.Close()
|
||||
}
|
||||
if s.d != nil {
|
||||
s.d.Stop(c)
|
||||
}
|
||||
s.ds.TearDownTest(c)
|
||||
}
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerRegistryAuthTokenSuite{
|
||||
ds: &DockerSuite{},
|
||||
})
|
||||
}
|
||||
|
||||
type DockerRegistryAuthTokenSuite struct {
|
||||
ds *DockerSuite
|
||||
reg *registry.V2
|
||||
d *daemon.Daemon
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthTokenSuite) OnTimeout(c *check.C) {
|
||||
s.d.DumpStackAndQuit()
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthTokenSuite) SetUpTest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, RegistryHosting, SameHostDaemon)
|
||||
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthTokenSuite) TearDownTest(c *check.C) {
|
||||
if s.reg != nil {
|
||||
out, err := s.d.Cmd("logout", privateRegistryURL)
|
||||
c.Assert(err, check.IsNil, check.Commentf("%s", out))
|
||||
s.reg.Close()
|
||||
}
|
||||
if s.d != nil {
|
||||
s.d.Stop(c)
|
||||
}
|
||||
s.ds.TearDownTest(c)
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthTokenSuite) setupRegistryWithTokenService(c *check.C, tokenURL string) {
|
||||
if s == nil {
|
||||
c.Fatal("registry suite isn't initialized")
|
||||
}
|
||||
s.reg = registry.NewV2(c, registry.Token(tokenURL))
|
||||
s.reg.WaitReady(c)
|
||||
}
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerDaemonSuite{
|
||||
ds: &DockerSuite{},
|
||||
})
|
||||
}
|
||||
|
||||
type DockerDaemonSuite struct {
|
||||
ds *DockerSuite
|
||||
d *daemon.Daemon
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) OnTimeout(c *check.C) {
|
||||
s.d.DumpStackAndQuit()
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) SetUpTest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TearDownTest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
if s.d != nil {
|
||||
s.d.Stop(c)
|
||||
}
|
||||
s.ds.TearDownTest(c)
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TearDownSuite(c *check.C) {
|
||||
filepath.Walk(testdaemon.SockRoot, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
// ignore errors here
|
||||
// not cleaning up sockets is not really an error
|
||||
return nil
|
||||
}
|
||||
if fi.Mode() == os.ModeSocket {
|
||||
syscall.Unlink(path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
os.RemoveAll(testdaemon.SockRoot)
|
||||
}
|
||||
|
||||
const defaultSwarmPort = 2477
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerSwarmSuite{
|
||||
ds: &DockerSuite{},
|
||||
})
|
||||
}
|
||||
|
||||
type DockerSwarmSuite struct {
|
||||
server *httptest.Server
|
||||
ds *DockerSuite
|
||||
daemons []*daemon.Daemon
|
||||
daemonsLock sync.Mutex // protect access to daemons
|
||||
portIndex int
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) OnTimeout(c *check.C) {
|
||||
s.daemonsLock.Lock()
|
||||
defer s.daemonsLock.Unlock()
|
||||
for _, d := range s.daemons {
|
||||
d.DumpStackAndQuit()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) SetUpTest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *daemon.Daemon {
|
||||
d := daemon.New(c, dockerBinary, dockerdBinary,
|
||||
testdaemon.WithEnvironment(testEnv.Execution),
|
||||
testdaemon.WithSwarmPort(defaultSwarmPort+s.portIndex),
|
||||
)
|
||||
if joinSwarm {
|
||||
if len(s.daemons) > 0 {
|
||||
d.StartAndSwarmJoin(c, s.daemons[0].Daemon, manager)
|
||||
} else {
|
||||
d.StartAndSwarmInit(c)
|
||||
}
|
||||
} else {
|
||||
d.StartWithBusybox(c, "--iptables=false", "--swarm-default-advertise-addr=lo")
|
||||
}
|
||||
|
||||
s.portIndex++
|
||||
s.daemonsLock.Lock()
|
||||
s.daemons = append(s.daemons, d)
|
||||
s.daemonsLock.Unlock()
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TearDownTest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
s.daemonsLock.Lock()
|
||||
for _, d := range s.daemons {
|
||||
if d != nil {
|
||||
d.Stop(c)
|
||||
d.Cleanup(c)
|
||||
}
|
||||
}
|
||||
s.daemons = nil
|
||||
s.daemonsLock.Unlock()
|
||||
|
||||
s.portIndex = 0
|
||||
s.ds.TearDownTest(c)
|
||||
}
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerPluginSuite{
|
||||
ds: &DockerSuite{},
|
||||
})
|
||||
}
|
||||
|
||||
type DockerPluginSuite struct {
|
||||
ds *DockerSuite
|
||||
registry *registry.V2
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) registryHost() string {
|
||||
return privateRegistryURL
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) getPluginRepo() string {
|
||||
return path.Join(ps.registryHost(), "plugin", "basic")
|
||||
}
|
||||
func (ps *DockerPluginSuite) getPluginRepoWithTag() string {
|
||||
return ps.getPluginRepo() + ":" + "latest"
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) SetUpSuite(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, RegistryHosting)
|
||||
ps.registry = registry.NewV2(c)
|
||||
ps.registry.WaitReady(c)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
err := plugin.CreateInRegistry(ctx, ps.getPluginRepo(), nil)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to create plugin"))
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TearDownSuite(c *check.C) {
|
||||
if ps.registry != nil {
|
||||
ps.registry.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TearDownTest(c *check.C) {
|
||||
ps.ds.TearDownTest(c)
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) OnTimeout(c *check.C) {
|
||||
ps.ds.OnTimeout(c)
|
||||
}
|
46
vendor/github.com/docker/docker-ce/components/engine/integration-cli/checker/checker.go
generated
vendored
Normal file
46
vendor/github.com/docker/docker-ce/components/engine/integration-cli/checker/checker.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Package checker provides Docker specific implementations of the go-check.Checker interface.
|
||||
package checker // import "github.com/docker/docker/integration-cli/checker"
|
||||
|
||||
import (
|
||||
"github.com/go-check/check"
|
||||
"github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// As a commodity, we bring all check.Checker variables into the current namespace to avoid having
|
||||
// to think about check.X versus checker.X.
|
||||
var (
|
||||
DeepEquals = check.DeepEquals
|
||||
ErrorMatches = check.ErrorMatches
|
||||
FitsTypeOf = check.FitsTypeOf
|
||||
HasLen = check.HasLen
|
||||
Implements = check.Implements
|
||||
IsNil = check.IsNil
|
||||
Matches = check.Matches
|
||||
Not = check.Not
|
||||
NotNil = check.NotNil
|
||||
PanicMatches = check.PanicMatches
|
||||
Panics = check.Panics
|
||||
|
||||
Contains = shakers.Contains
|
||||
ContainsAny = shakers.ContainsAny
|
||||
Count = shakers.Count
|
||||
Equals = shakers.Equals
|
||||
EqualFold = shakers.EqualFold
|
||||
False = shakers.False
|
||||
GreaterOrEqualThan = shakers.GreaterOrEqualThan
|
||||
GreaterThan = shakers.GreaterThan
|
||||
HasPrefix = shakers.HasPrefix
|
||||
HasSuffix = shakers.HasSuffix
|
||||
Index = shakers.Index
|
||||
IndexAny = shakers.IndexAny
|
||||
IsAfter = shakers.IsAfter
|
||||
IsBefore = shakers.IsBefore
|
||||
IsBetween = shakers.IsBetween
|
||||
IsLower = shakers.IsLower
|
||||
IsUpper = shakers.IsUpper
|
||||
LessOrEqualThan = shakers.LessOrEqualThan
|
||||
LessThan = shakers.LessThan
|
||||
TimeEquals = shakers.TimeEquals
|
||||
True = shakers.True
|
||||
TimeIgnore = shakers.TimeIgnore
|
||||
)
|
82
vendor/github.com/docker/docker-ce/components/engine/integration-cli/cli/build/build.go
generated
vendored
Normal file
82
vendor/github.com/docker/docker-ce/components/engine/integration-cli/cli/build/build.go
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
package build // import "github.com/docker/docker/integration-cli/cli/build"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/internal/test/fakecontext"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
type testingT interface {
|
||||
Fatal(args ...interface{})
|
||||
Fatalf(string, ...interface{})
|
||||
}
|
||||
|
||||
// WithStdinContext sets the build context from the standard input with the specified reader
|
||||
func WithStdinContext(closer io.ReadCloser) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Command = append(cmd.Command, "-")
|
||||
cmd.Stdin = closer
|
||||
return func() {
|
||||
// FIXME(vdemeester) we should not ignore the error here…
|
||||
closer.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithDockerfile creates / returns a CmdOperator to set the Dockerfile for a build operation
|
||||
func WithDockerfile(dockerfile string) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Command = append(cmd.Command, "-")
|
||||
cmd.Stdin = strings.NewReader(dockerfile)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithoutCache makes the build ignore cache
|
||||
func WithoutCache(cmd *icmd.Cmd) func() {
|
||||
cmd.Command = append(cmd.Command, "--no-cache")
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithContextPath sets the build context path
|
||||
func WithContextPath(path string) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Command = append(cmd.Command, path)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithExternalBuildContext use the specified context as build context
|
||||
func WithExternalBuildContext(ctx *fakecontext.Fake) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Dir = ctx.Dir
|
||||
cmd.Command = append(cmd.Command, ".")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithBuildContext sets up the build context
|
||||
func WithBuildContext(t testingT, contextOperators ...func(*fakecontext.Fake) error) func(*icmd.Cmd) func() {
|
||||
// FIXME(vdemeester) de-duplicate that
|
||||
ctx := fakecontext.New(t, "", contextOperators...)
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Dir = ctx.Dir
|
||||
cmd.Command = append(cmd.Command, ".")
|
||||
return closeBuildContext(t, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// WithFile adds the specified file (with content) in the build context
|
||||
func WithFile(name, content string) func(*fakecontext.Fake) error {
|
||||
return fakecontext.WithFile(name, content)
|
||||
}
|
||||
|
||||
func closeBuildContext(t testingT, ctx *fakecontext.Fake) func() {
|
||||
return func() {
|
||||
if err := ctx.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
226
vendor/github.com/docker/docker-ce/components/engine/integration-cli/cli/cli.go
generated
vendored
Normal file
226
vendor/github.com/docker/docker-ce/components/engine/integration-cli/cli/cli.go
generated
vendored
Normal file
|
@ -0,0 +1,226 @@
|
|||
package cli // import "github.com/docker/docker/integration-cli/cli"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/docker/docker/integration-cli/environment"
|
||||
"github.com/pkg/errors"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
var testEnv *environment.Execution
|
||||
|
||||
// SetTestEnvironment sets a static test environment
|
||||
// TODO: decouple this package from environment
|
||||
func SetTestEnvironment(env *environment.Execution) {
|
||||
testEnv = env
|
||||
}
|
||||
|
||||
// CmdOperator defines functions that can modify a command
|
||||
type CmdOperator func(*icmd.Cmd) func()
|
||||
|
||||
type testingT interface {
|
||||
assert.TestingT
|
||||
Fatal(args ...interface{})
|
||||
Fatalf(string, ...interface{})
|
||||
}
|
||||
|
||||
// DockerCmd executes the specified docker command and expect a success
|
||||
func DockerCmd(t testingT, args ...string) *icmd.Result {
|
||||
return Docker(Args(args...)).Assert(t, icmd.Success)
|
||||
}
|
||||
|
||||
// BuildCmd executes the specified docker build command and expect a success
|
||||
func BuildCmd(t testingT, name string, cmdOperators ...CmdOperator) *icmd.Result {
|
||||
return Docker(Build(name), cmdOperators...).Assert(t, icmd.Success)
|
||||
}
|
||||
|
||||
// InspectCmd executes the specified docker inspect command and expect a success
|
||||
func InspectCmd(t testingT, name string, cmdOperators ...CmdOperator) *icmd.Result {
|
||||
return Docker(Inspect(name), cmdOperators...).Assert(t, icmd.Success)
|
||||
}
|
||||
|
||||
// WaitRun will wait for the specified container to be running, maximum 5 seconds.
|
||||
func WaitRun(t testingT, name string, cmdOperators ...CmdOperator) {
|
||||
WaitForInspectResult(t, name, "{{.State.Running}}", "true", 5*time.Second, cmdOperators...)
|
||||
}
|
||||
|
||||
// WaitExited will wait for the specified container to state exit, subject
|
||||
// to a maximum time limit in seconds supplied by the caller
|
||||
func WaitExited(t testingT, name string, timeout time.Duration, cmdOperators ...CmdOperator) {
|
||||
WaitForInspectResult(t, name, "{{.State.Status}}", "exited", timeout, cmdOperators...)
|
||||
}
|
||||
|
||||
// WaitRestart will wait for the specified container to restart once
|
||||
func WaitRestart(t testingT, name string, timeout time.Duration, cmdOperators ...CmdOperator) {
|
||||
WaitForInspectResult(t, name, "{{.RestartCount}}", "1", timeout, cmdOperators...)
|
||||
}
|
||||
|
||||
// WaitForInspectResult waits for the specified expression to be equals to the specified expected string in the given time.
|
||||
func WaitForInspectResult(t testingT, name, expr, expected string, timeout time.Duration, cmdOperators ...CmdOperator) {
|
||||
after := time.After(timeout)
|
||||
|
||||
args := []string{"inspect", "-f", expr, name}
|
||||
for {
|
||||
result := Docker(Args(args...), cmdOperators...)
|
||||
if result.Error != nil {
|
||||
if !strings.Contains(strings.ToLower(result.Stderr()), "no such") {
|
||||
t.Fatalf("error executing docker inspect: %v\n%s",
|
||||
result.Stderr(), result.Stdout())
|
||||
}
|
||||
select {
|
||||
case <-after:
|
||||
t.Fatal(result.Error)
|
||||
default:
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
out := strings.TrimSpace(result.Stdout())
|
||||
if out == expected {
|
||||
break
|
||||
}
|
||||
|
||||
select {
|
||||
case <-after:
|
||||
t.Fatalf("condition \"%q == %q\" not true in time (%v)", out, expected, timeout)
|
||||
default:
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
// Docker executes the specified docker command
|
||||
func Docker(cmd icmd.Cmd, cmdOperators ...CmdOperator) *icmd.Result {
|
||||
for _, op := range cmdOperators {
|
||||
deferFn := op(&cmd)
|
||||
if deferFn != nil {
|
||||
defer deferFn()
|
||||
}
|
||||
}
|
||||
appendDocker(&cmd)
|
||||
if err := validateArgs(cmd.Command...); err != nil {
|
||||
return &icmd.Result{
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
return icmd.RunCmd(cmd)
|
||||
}
|
||||
|
||||
// validateArgs is a checker to ensure tests are not running commands which are
|
||||
// not supported on platforms. Specifically on Windows this is 'busybox top'.
|
||||
func validateArgs(args ...string) error {
|
||||
if testEnv.OSType != "windows" {
|
||||
return nil
|
||||
}
|
||||
foundBusybox := -1
|
||||
for key, value := range args {
|
||||
if strings.ToLower(value) == "busybox" {
|
||||
foundBusybox = key
|
||||
}
|
||||
if (foundBusybox != -1) && (key == foundBusybox+1) && (strings.ToLower(value) == "top") {
|
||||
return errors.New("cannot use 'busybox top' in tests on Windows. Use runSleepingContainer()")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build executes the specified docker build command
|
||||
func Build(name string) icmd.Cmd {
|
||||
return icmd.Command("build", "-t", name)
|
||||
}
|
||||
|
||||
// Inspect executes the specified docker inspect command
|
||||
func Inspect(name string) icmd.Cmd {
|
||||
return icmd.Command("inspect", name)
|
||||
}
|
||||
|
||||
// Format sets the specified format with --format flag
|
||||
func Format(format string) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Command = append(
|
||||
[]string{cmd.Command[0]},
|
||||
append([]string{"--format", fmt.Sprintf("{{%s}}", format)}, cmd.Command[1:]...)...,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func appendDocker(cmd *icmd.Cmd) {
|
||||
cmd.Command = append([]string{testEnv.DockerBinary()}, cmd.Command...)
|
||||
}
|
||||
|
||||
// Args build an icmd.Cmd struct from the specified arguments
|
||||
func Args(args ...string) icmd.Cmd {
|
||||
switch len(args) {
|
||||
case 0:
|
||||
return icmd.Cmd{}
|
||||
case 1:
|
||||
return icmd.Command(args[0])
|
||||
default:
|
||||
return icmd.Command(args[0], args[1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
// Daemon points to the specified daemon
|
||||
func Daemon(d *daemon.Daemon) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Command = append([]string{"--host", d.Sock()}, cmd.Command...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithTimeout sets the timeout for the command to run
|
||||
func WithTimeout(timeout time.Duration) func(cmd *icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Timeout = timeout
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnvironmentVariables sets the specified environment variables for the command to run
|
||||
func WithEnvironmentVariables(envs ...string) func(cmd *icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Env = envs
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithFlags sets the specified flags for the command to run
|
||||
func WithFlags(flags ...string) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Command = append(cmd.Command, flags...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// InDir sets the folder in which the command should be executed
|
||||
func InDir(path string) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Dir = path
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithStdout sets the standard output writer of the command
|
||||
func WithStdout(writer io.Writer) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Stdout = writer
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithStdin sets the standard input reader for the command
|
||||
func WithStdin(stdin io.Reader) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Stdin = stdin
|
||||
return nil
|
||||
}
|
||||
}
|
143
vendor/github.com/docker/docker-ce/components/engine/integration-cli/daemon/daemon.go
generated
vendored
Normal file
143
vendor/github.com/docker/docker-ce/components/engine/integration-cli/daemon/daemon.go
generated
vendored
Normal file
|
@ -0,0 +1,143 @@
|
|||
package daemon // import "github.com/docker/docker/integration-cli/daemon"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/go-check/check"
|
||||
"github.com/pkg/errors"
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
type testingT interface {
|
||||
assert.TestingT
|
||||
logT
|
||||
Fatalf(string, ...interface{})
|
||||
}
|
||||
|
||||
type logT interface {
|
||||
Logf(string, ...interface{})
|
||||
}
|
||||
|
||||
// Daemon represents a Docker daemon for the testing framework.
|
||||
type Daemon struct {
|
||||
*daemon.Daemon
|
||||
dockerBinary string
|
||||
}
|
||||
|
||||
// New returns a Daemon instance to be used for testing.
|
||||
// This will create a directory such as d123456789 in the folder specified by $DOCKER_INTEGRATION_DAEMON_DEST or $DEST.
|
||||
// The daemon will not automatically start.
|
||||
func New(t testingT, dockerBinary string, dockerdBinary string, ops ...func(*daemon.Daemon)) *Daemon {
|
||||
ops = append(ops, daemon.WithDockerdBinary(dockerdBinary))
|
||||
d := daemon.New(t, ops...)
|
||||
return &Daemon{
|
||||
Daemon: d,
|
||||
dockerBinary: dockerBinary,
|
||||
}
|
||||
}
|
||||
|
||||
// Cmd executes a docker CLI command against this daemon.
|
||||
// Example: d.Cmd("version") will run docker -H unix://path/to/unix.sock version
|
||||
func (d *Daemon) Cmd(args ...string) (string, error) {
|
||||
result := icmd.RunCmd(d.Command(args...))
|
||||
return result.Combined(), result.Error
|
||||
}
|
||||
|
||||
// Command creates a docker CLI command against this daemon, to be executed later.
|
||||
// Example: d.Command("version") creates a command to run "docker -H unix://path/to/unix.sock version"
|
||||
func (d *Daemon) Command(args ...string) icmd.Cmd {
|
||||
return icmd.Command(d.dockerBinary, d.PrependHostArg(args)...)
|
||||
}
|
||||
|
||||
// PrependHostArg prepend the specified arguments by the daemon host flags
|
||||
func (d *Daemon) PrependHostArg(args []string) []string {
|
||||
for _, arg := range args {
|
||||
if arg == "--host" || arg == "-H" {
|
||||
return args
|
||||
}
|
||||
}
|
||||
return append([]string{"--host", d.Sock()}, args...)
|
||||
}
|
||||
|
||||
// GetIDByName returns the ID of an object (container, volume, …) given its name
|
||||
func (d *Daemon) GetIDByName(name string) (string, error) {
|
||||
return d.inspectFieldWithError(name, "Id")
|
||||
}
|
||||
|
||||
// InspectField returns the field filter by 'filter'
|
||||
func (d *Daemon) InspectField(name, filter string) (string, error) {
|
||||
return d.inspectFilter(name, filter)
|
||||
}
|
||||
|
||||
func (d *Daemon) inspectFilter(name, filter string) (string, error) {
|
||||
format := fmt.Sprintf("{{%s}}", filter)
|
||||
out, err := d.Cmd("inspect", "-f", format, name)
|
||||
if err != nil {
|
||||
return "", errors.Errorf("failed to inspect %s: %s", name, out)
|
||||
}
|
||||
return strings.TrimSpace(out), nil
|
||||
}
|
||||
|
||||
func (d *Daemon) inspectFieldWithError(name, field string) (string, error) {
|
||||
return d.inspectFilter(name, fmt.Sprintf(".%s", field))
|
||||
}
|
||||
|
||||
// CheckActiveContainerCount returns the number of active containers
|
||||
// FIXME(vdemeester) should re-use ActivateContainers in some way
|
||||
func (d *Daemon) CheckActiveContainerCount(c *check.C) (interface{}, check.CommentInterface) {
|
||||
out, err := d.Cmd("ps", "-q")
|
||||
c.Assert(err, checker.IsNil)
|
||||
if len(strings.TrimSpace(out)) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return len(strings.Split(strings.TrimSpace(out), "\n")), check.Commentf("output: %q", string(out))
|
||||
}
|
||||
|
||||
// WaitRun waits for a container to be running for 10s
|
||||
func (d *Daemon) WaitRun(contID string) error {
|
||||
args := []string{"--host", d.Sock()}
|
||||
return WaitInspectWithArgs(d.dockerBinary, contID, "{{.State.Running}}", "true", 10*time.Second, args...)
|
||||
}
|
||||
|
||||
// WaitInspectWithArgs waits for the specified expression to be equals to the specified expected string in the given time.
|
||||
// Deprecated: use cli.WaitCmd instead
|
||||
func WaitInspectWithArgs(dockerBinary, name, expr, expected string, timeout time.Duration, arg ...string) error {
|
||||
after := time.After(timeout)
|
||||
|
||||
args := append(arg, "inspect", "-f", expr, name)
|
||||
for {
|
||||
result := icmd.RunCommand(dockerBinary, args...)
|
||||
if result.Error != nil {
|
||||
if !strings.Contains(strings.ToLower(result.Stderr()), "no such") {
|
||||
return errors.Errorf("error executing docker inspect: %v\n%s",
|
||||
result.Stderr(), result.Stdout())
|
||||
}
|
||||
select {
|
||||
case <-after:
|
||||
return result.Error
|
||||
default:
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
out := strings.TrimSpace(result.Stdout())
|
||||
if out == expected {
|
||||
break
|
||||
}
|
||||
|
||||
select {
|
||||
case <-after:
|
||||
return errors.Errorf("condition \"%q == %q\" not true in time (%v)", out, expected, timeout)
|
||||
default:
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
return nil
|
||||
}
|
197
vendor/github.com/docker/docker-ce/components/engine/integration-cli/daemon/daemon_swarm.go
generated
vendored
Normal file
197
vendor/github.com/docker/docker-ce/components/engine/integration-cli/daemon/daemon_swarm.go
generated
vendored
Normal file
|
@ -0,0 +1,197 @@
|
|||
package daemon // import "github.com/docker/docker/integration-cli/daemon"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
// CheckServiceTasksInState returns the number of tasks with a matching state,
|
||||
// and optional message substring.
|
||||
func (d *Daemon) CheckServiceTasksInState(service string, state swarm.TaskState, message string) func(*check.C) (interface{}, check.CommentInterface) {
|
||||
return func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks := d.GetServiceTasks(c, service)
|
||||
var count int
|
||||
for _, task := range tasks {
|
||||
if task.Status.State == state {
|
||||
if message == "" || strings.Contains(task.Status.Message, message) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CheckServiceTasksInStateWithError returns the number of tasks with a matching state,
|
||||
// and optional message substring.
|
||||
func (d *Daemon) CheckServiceTasksInStateWithError(service string, state swarm.TaskState, errorMessage string) func(*check.C) (interface{}, check.CommentInterface) {
|
||||
return func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks := d.GetServiceTasks(c, service)
|
||||
var count int
|
||||
for _, task := range tasks {
|
||||
if task.Status.State == state {
|
||||
if errorMessage == "" || strings.Contains(task.Status.Err, errorMessage) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CheckServiceRunningTasks returns the number of running tasks for the specified service
|
||||
func (d *Daemon) CheckServiceRunningTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
|
||||
return d.CheckServiceTasksInState(service, swarm.TaskStateRunning, "")
|
||||
}
|
||||
|
||||
// CheckServiceUpdateState returns the current update state for the specified service
|
||||
func (d *Daemon) CheckServiceUpdateState(service string) func(*check.C) (interface{}, check.CommentInterface) {
|
||||
return func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
service := d.GetService(c, service)
|
||||
if service.UpdateStatus == nil {
|
||||
return "", nil
|
||||
}
|
||||
return service.UpdateStatus.State, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CheckPluginRunning returns the runtime state of the plugin
|
||||
func (d *Daemon) CheckPluginRunning(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
return func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
apiclient, err := d.NewClient()
|
||||
assert.NilError(c, err)
|
||||
resp, _, err := apiclient.PluginInspectWithRaw(context.Background(), plugin)
|
||||
if client.IsErrNotFound(err) {
|
||||
return false, check.Commentf("%v", err)
|
||||
}
|
||||
assert.NilError(c, err)
|
||||
return resp.Enabled, check.Commentf("%+v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckPluginImage returns the runtime state of the plugin
|
||||
func (d *Daemon) CheckPluginImage(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
return func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
apiclient, err := d.NewClient()
|
||||
assert.NilError(c, err)
|
||||
resp, _, err := apiclient.PluginInspectWithRaw(context.Background(), plugin)
|
||||
if client.IsErrNotFound(err) {
|
||||
return false, check.Commentf("%v", err)
|
||||
}
|
||||
assert.NilError(c, err)
|
||||
return resp.PluginReference, check.Commentf("%+v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckServiceTasks returns the number of tasks for the specified service
|
||||
func (d *Daemon) CheckServiceTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
|
||||
return func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks := d.GetServiceTasks(c, service)
|
||||
return len(tasks), nil
|
||||
}
|
||||
}
|
||||
|
||||
// CheckRunningTaskNetworks returns the number of times each network is referenced from a task.
|
||||
func (d *Daemon) CheckRunningTaskNetworks(c *check.C) (interface{}, check.CommentInterface) {
|
||||
cli, err := d.NewClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
filterArgs := filters.NewArgs()
|
||||
filterArgs.Add("desired-state", "running")
|
||||
|
||||
options := types.TaskListOptions{
|
||||
Filters: filterArgs,
|
||||
}
|
||||
|
||||
tasks, err := cli.TaskList(context.Background(), options)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
result := make(map[string]int)
|
||||
for _, task := range tasks {
|
||||
for _, network := range task.Spec.Networks {
|
||||
result[network.Target]++
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CheckRunningTaskImages returns the times each image is running as a task.
|
||||
func (d *Daemon) CheckRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) {
|
||||
cli, err := d.NewClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
filterArgs := filters.NewArgs()
|
||||
filterArgs.Add("desired-state", "running")
|
||||
|
||||
options := types.TaskListOptions{
|
||||
Filters: filterArgs,
|
||||
}
|
||||
|
||||
tasks, err := cli.TaskList(context.Background(), options)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
result := make(map[string]int)
|
||||
for _, task := range tasks {
|
||||
if task.Status.State == swarm.TaskStateRunning && task.Spec.ContainerSpec != nil {
|
||||
result[task.Spec.ContainerSpec.Image]++
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CheckNodeReadyCount returns the number of ready node on the swarm
|
||||
func (d *Daemon) CheckNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) {
|
||||
nodes := d.ListNodes(c)
|
||||
var readyCount int
|
||||
for _, node := range nodes {
|
||||
if node.Status.State == swarm.NodeStateReady {
|
||||
readyCount++
|
||||
}
|
||||
}
|
||||
return readyCount, nil
|
||||
}
|
||||
|
||||
// CheckLocalNodeState returns the current swarm node state
|
||||
func (d *Daemon) CheckLocalNodeState(c *check.C) (interface{}, check.CommentInterface) {
|
||||
info := d.SwarmInfo(c)
|
||||
return info.LocalNodeState, nil
|
||||
}
|
||||
|
||||
// CheckControlAvailable returns the current swarm control available
|
||||
func (d *Daemon) CheckControlAvailable(c *check.C) (interface{}, check.CommentInterface) {
|
||||
info := d.SwarmInfo(c)
|
||||
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
|
||||
return info.ControlAvailable, nil
|
||||
}
|
||||
|
||||
// CheckLeader returns whether there is a leader on the swarm or not
|
||||
func (d *Daemon) CheckLeader(c *check.C) (interface{}, check.CommentInterface) {
|
||||
cli, err := d.NewClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
errList := check.Commentf("could not get node list")
|
||||
|
||||
ls, err := cli.NodeList(context.Background(), types.NodeListOptions{})
|
||||
if err != nil {
|
||||
return err, errList
|
||||
}
|
||||
|
||||
for _, node := range ls {
|
||||
if node.ManagerStatus != nil && node.ManagerStatus.Leader {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("no leader"), check.Commentf("could not find leader")
|
||||
}
|
23
vendor/github.com/docker/docker-ce/components/engine/integration-cli/daemon_swarm_hack_test.go
generated
vendored
Normal file
23
vendor/github.com/docker/docker-ce/components/engine/integration-cli/daemon_swarm_hack_test.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) getDaemon(c *check.C, nodeID string) *daemon.Daemon {
|
||||
s.daemonsLock.Lock()
|
||||
defer s.daemonsLock.Unlock()
|
||||
for _, d := range s.daemons {
|
||||
if d.NodeID() == nodeID {
|
||||
return d
|
||||
}
|
||||
}
|
||||
c.Fatalf("could not find node with id: %s", nodeID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// nodeCmd executes a command on a given node via the normal docker socket
|
||||
func (s *DockerSwarmSuite) nodeCmd(c *check.C, id string, args ...string) (string, error) {
|
||||
return s.getDaemon(c, id).Cmd(args...)
|
||||
}
|
260
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_attach_test.go
generated
vendored
Normal file
260
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_attach_test.go
generated
vendored
Normal file
|
@ -0,0 +1,260 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/go-check/check"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestGetContainersAttachWebsocket(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-dit", "busybox", "cat")
|
||||
|
||||
rwc, err := request.SockConn(time.Duration(10*time.Second), daemonHost())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
config, err := websocket.NewConfig(
|
||||
"/containers/"+cleanedContainerID+"/attach/ws?stream=1&stdin=1&stdout=1&stderr=1",
|
||||
"http://localhost",
|
||||
)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
ws, err := websocket.NewClient(config, rwc)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer ws.Close()
|
||||
|
||||
expected := []byte("hello")
|
||||
actual := make([]byte, len(expected))
|
||||
|
||||
outChan := make(chan error)
|
||||
go func() {
|
||||
_, err := io.ReadFull(ws, actual)
|
||||
outChan <- err
|
||||
close(outChan)
|
||||
}()
|
||||
|
||||
inChan := make(chan error)
|
||||
go func() {
|
||||
_, err := ws.Write(expected)
|
||||
inChan <- err
|
||||
close(inChan)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-inChan:
|
||||
c.Assert(err, checker.IsNil)
|
||||
case <-time.After(5 * time.Second):
|
||||
c.Fatal("Timeout writing to ws")
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-outChan:
|
||||
c.Assert(err, checker.IsNil)
|
||||
case <-time.After(5 * time.Second):
|
||||
c.Fatal("Timeout reading from ws")
|
||||
}
|
||||
|
||||
c.Assert(actual, checker.DeepEquals, expected, check.Commentf("Websocket didn't return the expected data"))
|
||||
}
|
||||
|
||||
// regression gh14320
|
||||
func (s *DockerSuite) TestPostContainersAttachContainerNotFound(c *check.C) {
|
||||
resp, _, err := request.Post("/containers/doesnotexist/attach")
|
||||
c.Assert(err, checker.IsNil)
|
||||
// connection will shutdown, err should be "persistent connection closed"
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound)
|
||||
content, err := request.ReadBody(resp.Body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
expected := "No such container: doesnotexist\r\n"
|
||||
c.Assert(string(content), checker.Equals, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestGetContainersWsAttachContainerNotFound(c *check.C) {
|
||||
res, body, err := request.Get("/containers/doesnotexist/attach/ws")
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusNotFound)
|
||||
c.Assert(err, checker.IsNil)
|
||||
b, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
expected := "No such container: doesnotexist"
|
||||
c.Assert(getErrorMessage(c, b), checker.Contains, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPostContainersAttach(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
expectSuccess := func(conn net.Conn, br *bufio.Reader, stream string, tty bool) {
|
||||
defer conn.Close()
|
||||
expected := []byte("success")
|
||||
_, err := conn.Write(expected)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
conn.SetReadDeadline(time.Now().Add(time.Second))
|
||||
lenHeader := 0
|
||||
if !tty {
|
||||
lenHeader = 8
|
||||
}
|
||||
actual := make([]byte, len(expected)+lenHeader)
|
||||
_, err = io.ReadFull(br, actual)
|
||||
c.Assert(err, checker.IsNil)
|
||||
if !tty {
|
||||
fdMap := map[string]byte{
|
||||
"stdin": 0,
|
||||
"stdout": 1,
|
||||
"stderr": 2,
|
||||
}
|
||||
c.Assert(actual[0], checker.Equals, fdMap[stream])
|
||||
}
|
||||
c.Assert(actual[lenHeader:], checker.DeepEquals, expected, check.Commentf("Attach didn't return the expected data from %s", stream))
|
||||
}
|
||||
|
||||
expectTimeout := func(conn net.Conn, br *bufio.Reader, stream string) {
|
||||
defer conn.Close()
|
||||
_, err := conn.Write([]byte{'t'})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
conn.SetReadDeadline(time.Now().Add(time.Second))
|
||||
actual := make([]byte, 1)
|
||||
_, err = io.ReadFull(br, actual)
|
||||
opErr, ok := err.(*net.OpError)
|
||||
c.Assert(ok, checker.Equals, true, check.Commentf("Error is expected to be *net.OpError, got %v", err))
|
||||
c.Assert(opErr.Timeout(), checker.Equals, true, check.Commentf("Read from %s is expected to timeout", stream))
|
||||
}
|
||||
|
||||
// Create a container that only emits stdout.
|
||||
cid, _ := dockerCmd(c, "run", "-di", "busybox", "cat")
|
||||
cid = strings.TrimSpace(cid)
|
||||
// Attach to the container's stdout stream.
|
||||
conn, br, err := sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stdout=1", nil, "text/plain", daemonHost())
|
||||
c.Assert(err, checker.IsNil)
|
||||
// Check if the data from stdout can be received.
|
||||
expectSuccess(conn, br, "stdout", false)
|
||||
// Attach to the container's stderr stream.
|
||||
conn, br, err = sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stderr=1", nil, "text/plain", daemonHost())
|
||||
c.Assert(err, checker.IsNil)
|
||||
// Since the container only emits stdout, attaching to stderr should return nothing.
|
||||
expectTimeout(conn, br, "stdout")
|
||||
|
||||
// Test the similar functions of the stderr stream.
|
||||
cid, _ = dockerCmd(c, "run", "-di", "busybox", "/bin/sh", "-c", "cat >&2")
|
||||
cid = strings.TrimSpace(cid)
|
||||
conn, br, err = sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stderr=1", nil, "text/plain", daemonHost())
|
||||
c.Assert(err, checker.IsNil)
|
||||
expectSuccess(conn, br, "stderr", false)
|
||||
conn, br, err = sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stdout=1", nil, "text/plain", daemonHost())
|
||||
c.Assert(err, checker.IsNil)
|
||||
expectTimeout(conn, br, "stderr")
|
||||
|
||||
// Test with tty.
|
||||
cid, _ = dockerCmd(c, "run", "-dit", "busybox", "/bin/sh", "-c", "cat >&2")
|
||||
cid = strings.TrimSpace(cid)
|
||||
// Attach to stdout only.
|
||||
conn, br, err = sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stdout=1", nil, "text/plain", daemonHost())
|
||||
c.Assert(err, checker.IsNil)
|
||||
expectSuccess(conn, br, "stdout", true)
|
||||
|
||||
// Attach without stdout stream.
|
||||
conn, br, err = sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stderr=1", nil, "text/plain", daemonHost())
|
||||
c.Assert(err, checker.IsNil)
|
||||
// Nothing should be received because both the stdout and stderr of the container will be
|
||||
// sent to the client as stdout when tty is enabled.
|
||||
expectTimeout(conn, br, "stdout")
|
||||
|
||||
// Test the client API
|
||||
client, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer client.Close()
|
||||
|
||||
cid, _ = dockerCmd(c, "run", "-di", "busybox", "/bin/sh", "-c", "echo hello; cat")
|
||||
cid = strings.TrimSpace(cid)
|
||||
|
||||
// Make sure we don't see "hello" if Logs is false
|
||||
attachOpts := types.ContainerAttachOptions{
|
||||
Stream: true,
|
||||
Stdin: true,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Logs: false,
|
||||
}
|
||||
|
||||
resp, err := client.ContainerAttach(context.Background(), cid, attachOpts)
|
||||
c.Assert(err, checker.IsNil)
|
||||
expectSuccess(resp.Conn, resp.Reader, "stdout", false)
|
||||
|
||||
// Make sure we do see "hello" if Logs is true
|
||||
attachOpts.Logs = true
|
||||
resp, err = client.ContainerAttach(context.Background(), cid, attachOpts)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
defer resp.Conn.Close()
|
||||
resp.Conn.SetReadDeadline(time.Now().Add(time.Second))
|
||||
|
||||
_, err = resp.Conn.Write([]byte("success"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var outBuf, errBuf bytes.Buffer
|
||||
_, err = stdcopy.StdCopy(&outBuf, &errBuf, resp.Reader)
|
||||
if err != nil && errors.Cause(err).(net.Error).Timeout() {
|
||||
// ignore the timeout error as it is expected
|
||||
err = nil
|
||||
}
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(errBuf.String(), checker.Equals, "")
|
||||
c.Assert(outBuf.String(), checker.Equals, "hello\nsuccess")
|
||||
}
|
||||
|
||||
// SockRequestHijack creates a connection to specified host (with method, contenttype, …) and returns a hijacked connection
|
||||
// and the output as a `bufio.Reader`
|
||||
func sockRequestHijack(method, endpoint string, data io.Reader, ct string, daemon string, modifiers ...func(*http.Request)) (net.Conn, *bufio.Reader, error) {
|
||||
req, client, err := newRequestClient(method, endpoint, data, ct, daemon, modifiers...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
client.Do(req)
|
||||
conn, br := client.Hijack()
|
||||
return conn, br, nil
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) httputil.ClientConn is deprecated, use http.Client instead (closer to actual client)
|
||||
// Deprecated: Use New instead of NewRequestClient
|
||||
// Deprecated: use request.Do (or Get, Delete, Post) instead
|
||||
func newRequestClient(method, endpoint string, data io.Reader, ct, daemon string, modifiers ...func(*http.Request)) (*http.Request, *httputil.ClientConn, error) {
|
||||
c, err := request.SockConn(time.Duration(10*time.Second), daemon)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not dial docker daemon: %v", err)
|
||||
}
|
||||
|
||||
client := httputil.NewClientConn(c, nil)
|
||||
|
||||
req, err := http.NewRequest(method, endpoint, data)
|
||||
if err != nil {
|
||||
client.Close()
|
||||
return nil, nil, fmt.Errorf("could not create new request: %v", err)
|
||||
}
|
||||
|
||||
for _, opt := range modifiers {
|
||||
opt(req)
|
||||
}
|
||||
|
||||
if ct != "" {
|
||||
req.Header.Set("Content-Type", ct)
|
||||
}
|
||||
return req, client, nil
|
||||
}
|
558
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_build_test.go
generated
vendored
Normal file
558
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_build_test.go
generated
vendored
Normal file
|
@ -0,0 +1,558 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/fakecontext"
|
||||
"github.com/docker/docker/internal/test/fakegit"
|
||||
"github.com/docker/docker/internal/test/fakestorage"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestBuildAPIDockerFileRemote(c *check.C) {
|
||||
testRequires(c, NotUserNamespace)
|
||||
|
||||
var testD string
|
||||
if testEnv.OSType == "windows" {
|
||||
testD = `FROM busybox
|
||||
RUN find / -name ba*
|
||||
RUN find /tmp/`
|
||||
} else {
|
||||
// -xdev is required because sysfs can cause EPERM
|
||||
testD = `FROM busybox
|
||||
RUN find / -xdev -name ba*
|
||||
RUN find /tmp/`
|
||||
}
|
||||
server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{"testD": testD}))
|
||||
defer server.Close()
|
||||
|
||||
res, body, err := request.Post("/build?dockerfile=baz&remote="+server.URL()+"/testD", request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
buf, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Make sure Dockerfile exists.
|
||||
// Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
|
||||
out := string(buf)
|
||||
c.Assert(out, checker.Contains, "RUN find /tmp")
|
||||
c.Assert(out, checker.Not(checker.Contains), "baz")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildAPIRemoteTarballContext(c *check.C) {
|
||||
buffer := new(bytes.Buffer)
|
||||
tw := tar.NewWriter(buffer)
|
||||
defer tw.Close()
|
||||
|
||||
dockerfile := []byte("FROM busybox")
|
||||
err := tw.WriteHeader(&tar.Header{
|
||||
Name: "Dockerfile",
|
||||
Size: int64(len(dockerfile)),
|
||||
})
|
||||
// failed to write tar file header
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = tw.Write(dockerfile)
|
||||
// failed to write tar file content
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// failed to close tar archive
|
||||
c.Assert(tw.Close(), checker.IsNil)
|
||||
|
||||
server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{
|
||||
"testT.tar": buffer,
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
res, b, err := request.Post("/build?remote="+server.URL()+"/testT.tar", request.ContentType("application/tar"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
b.Close()
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildAPIRemoteTarballContextWithCustomDockerfile(c *check.C) {
|
||||
buffer := new(bytes.Buffer)
|
||||
tw := tar.NewWriter(buffer)
|
||||
defer tw.Close()
|
||||
|
||||
dockerfile := []byte(`FROM busybox
|
||||
RUN echo 'wrong'`)
|
||||
err := tw.WriteHeader(&tar.Header{
|
||||
Name: "Dockerfile",
|
||||
Size: int64(len(dockerfile)),
|
||||
})
|
||||
// failed to write tar file header
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = tw.Write(dockerfile)
|
||||
// failed to write tar file content
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
custom := []byte(`FROM busybox
|
||||
RUN echo 'right'
|
||||
`)
|
||||
err = tw.WriteHeader(&tar.Header{
|
||||
Name: "custom",
|
||||
Size: int64(len(custom)),
|
||||
})
|
||||
|
||||
// failed to write tar file header
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = tw.Write(custom)
|
||||
// failed to write tar file content
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// failed to close tar archive
|
||||
c.Assert(tw.Close(), checker.IsNil)
|
||||
|
||||
server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{
|
||||
"testT.tar": buffer,
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
url := "/build?dockerfile=custom&remote=" + server.URL() + "/testT.tar"
|
||||
res, body, err := request.Post(url, request.ContentType("application/tar"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
defer body.Close()
|
||||
content, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Build used the wrong dockerfile.
|
||||
c.Assert(string(content), checker.Not(checker.Contains), "wrong")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildAPILowerDockerfile(c *check.C) {
|
||||
git := fakegit.New(c, "repo", map[string]string{
|
||||
"dockerfile": `FROM busybox
|
||||
RUN echo from dockerfile`,
|
||||
}, false)
|
||||
defer git.Close()
|
||||
|
||||
res, body, err := request.Post("/build?remote="+git.RepoURL, request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
buf, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out := string(buf)
|
||||
c.Assert(out, checker.Contains, "from dockerfile")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildAPIBuildGitWithF(c *check.C) {
|
||||
git := fakegit.New(c, "repo", map[string]string{
|
||||
"baz": `FROM busybox
|
||||
RUN echo from baz`,
|
||||
"Dockerfile": `FROM busybox
|
||||
RUN echo from Dockerfile`,
|
||||
}, false)
|
||||
defer git.Close()
|
||||
|
||||
// Make sure it tries to 'dockerfile' query param value
|
||||
res, body, err := request.Post("/build?dockerfile=baz&remote="+git.RepoURL, request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
buf, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out := string(buf)
|
||||
c.Assert(out, checker.Contains, "from baz")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildAPIDoubleDockerfile(c *check.C) {
|
||||
testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows
|
||||
git := fakegit.New(c, "repo", map[string]string{
|
||||
"Dockerfile": `FROM busybox
|
||||
RUN echo from Dockerfile`,
|
||||
"dockerfile": `FROM busybox
|
||||
RUN echo from dockerfile`,
|
||||
}, false)
|
||||
defer git.Close()
|
||||
|
||||
// Make sure it tries to 'dockerfile' query param value
|
||||
res, body, err := request.Post("/build?remote="+git.RepoURL, request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
buf, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out := string(buf)
|
||||
c.Assert(out, checker.Contains, "from Dockerfile")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildAPIUnnormalizedTarPaths(c *check.C) {
|
||||
// Make sure that build context tars with entries of the form
|
||||
// x/./y don't cause caching false positives.
|
||||
|
||||
buildFromTarContext := func(fileContents []byte) string {
|
||||
buffer := new(bytes.Buffer)
|
||||
tw := tar.NewWriter(buffer)
|
||||
defer tw.Close()
|
||||
|
||||
dockerfile := []byte(`FROM busybox
|
||||
COPY dir /dir/`)
|
||||
err := tw.WriteHeader(&tar.Header{
|
||||
Name: "Dockerfile",
|
||||
Size: int64(len(dockerfile)),
|
||||
})
|
||||
//failed to write tar file header
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = tw.Write(dockerfile)
|
||||
// failed to write Dockerfile in tar file content
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = tw.WriteHeader(&tar.Header{
|
||||
Name: "dir/./file",
|
||||
Size: int64(len(fileContents)),
|
||||
})
|
||||
//failed to write tar file header
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = tw.Write(fileContents)
|
||||
// failed to write file contents in tar file content
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// failed to close tar archive
|
||||
c.Assert(tw.Close(), checker.IsNil)
|
||||
|
||||
res, body, err := request.Post("/build", request.RawContent(ioutil.NopCloser(buffer)), request.ContentType("application/x-tar"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
out, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
lines := strings.Split(string(out), "\n")
|
||||
c.Assert(len(lines), checker.GreaterThan, 1)
|
||||
c.Assert(lines[len(lines)-2], checker.Matches, ".*Successfully built [0-9a-f]{12}.*")
|
||||
|
||||
re := regexp.MustCompile("Successfully built ([0-9a-f]{12})")
|
||||
matches := re.FindStringSubmatch(lines[len(lines)-2])
|
||||
return matches[1]
|
||||
}
|
||||
|
||||
imageA := buildFromTarContext([]byte("abc"))
|
||||
imageB := buildFromTarContext([]byte("def"))
|
||||
|
||||
c.Assert(imageA, checker.Not(checker.Equals), imageB)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildOnBuildWithCopy(c *check.C) {
|
||||
dockerfile := `
|
||||
FROM ` + minimalBaseImage() + ` as onbuildbase
|
||||
ONBUILD COPY file /file
|
||||
|
||||
FROM onbuildbase
|
||||
`
|
||||
ctx := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
fakecontext.WithFile("file", "some content"),
|
||||
)
|
||||
defer ctx.Close()
|
||||
|
||||
res, body, err := request.Post(
|
||||
"/build",
|
||||
request.RawContent(ctx.AsTarReader(c)),
|
||||
request.ContentType("application/x-tar"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
out, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(out), checker.Contains, "Successfully built")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildOnBuildCache(c *check.C) {
|
||||
build := func(dockerfile string) []byte {
|
||||
ctx := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
)
|
||||
defer ctx.Close()
|
||||
|
||||
res, body, err := request.Post(
|
||||
"/build",
|
||||
request.RawContent(ctx.AsTarReader(c)),
|
||||
request.ContentType("application/x-tar"))
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.DeepEqual(http.StatusOK, res.StatusCode))
|
||||
|
||||
out, err := request.ReadBody(body)
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.Contains(string(out), "Successfully built"))
|
||||
return out
|
||||
}
|
||||
|
||||
dockerfile := `
|
||||
FROM ` + minimalBaseImage() + ` as onbuildbase
|
||||
ENV something=bar
|
||||
ONBUILD ENV foo=bar
|
||||
`
|
||||
build(dockerfile)
|
||||
|
||||
dockerfile += "FROM onbuildbase"
|
||||
out := build(dockerfile)
|
||||
|
||||
imageIDs := getImageIDsFromBuild(c, out)
|
||||
assert.Check(c, is.Len(imageIDs, 2))
|
||||
parentID, childID := imageIDs[0], imageIDs[1]
|
||||
|
||||
client := testEnv.APIClient()
|
||||
|
||||
// check parentID is correct
|
||||
image, _, err := client.ImageInspectWithRaw(context.Background(), childID)
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.Equal(parentID, image.Parent))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestBuildCopyFromForcePull(c *check.C) {
|
||||
client := testEnv.APIClient()
|
||||
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
// tag the image to upload it to the private registry
|
||||
err := client.ImageTag(context.TODO(), "busybox", repoName)
|
||||
assert.Check(c, err)
|
||||
// push the image to the registry
|
||||
rc, err := client.ImagePush(context.TODO(), repoName, types.ImagePushOptions{RegistryAuth: "{}"})
|
||||
assert.Check(c, err)
|
||||
_, err = io.Copy(ioutil.Discard, rc)
|
||||
assert.Check(c, err)
|
||||
|
||||
dockerfile := fmt.Sprintf(`
|
||||
FROM %s AS foo
|
||||
RUN touch abc
|
||||
FROM %s
|
||||
COPY --from=foo /abc /
|
||||
`, repoName, repoName)
|
||||
|
||||
ctx := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
)
|
||||
defer ctx.Close()
|
||||
|
||||
res, body, err := request.Post(
|
||||
"/build?pull=1",
|
||||
request.RawContent(ctx.AsTarReader(c)),
|
||||
request.ContentType("application/x-tar"))
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.DeepEqual(http.StatusOK, res.StatusCode))
|
||||
|
||||
out, err := request.ReadBody(body)
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.Contains(string(out), "Successfully built"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildAddRemoteNoDecompress(c *check.C) {
|
||||
buffer := new(bytes.Buffer)
|
||||
tw := tar.NewWriter(buffer)
|
||||
dt := []byte("contents")
|
||||
err := tw.WriteHeader(&tar.Header{
|
||||
Name: "foo",
|
||||
Size: int64(len(dt)),
|
||||
Mode: 0600,
|
||||
Typeflag: tar.TypeReg,
|
||||
})
|
||||
assert.NilError(c, err)
|
||||
_, err = tw.Write(dt)
|
||||
assert.NilError(c, err)
|
||||
err = tw.Close()
|
||||
assert.NilError(c, err)
|
||||
|
||||
server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{
|
||||
"test.tar": buffer,
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
dockerfile := fmt.Sprintf(`
|
||||
FROM busybox
|
||||
ADD %s/test.tar /
|
||||
RUN [ -f test.tar ]
|
||||
`, server.URL())
|
||||
|
||||
ctx := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
)
|
||||
defer ctx.Close()
|
||||
|
||||
res, body, err := request.Post(
|
||||
"/build",
|
||||
request.RawContent(ctx.AsTarReader(c)),
|
||||
request.ContentType("application/x-tar"))
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.DeepEqual(http.StatusOK, res.StatusCode))
|
||||
|
||||
out, err := request.ReadBody(body)
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.Contains(string(out), "Successfully built"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildChownOnCopy(c *check.C) {
|
||||
// new feature added in 1.31 - https://github.com/moby/moby/pull/34263
|
||||
testRequires(c, DaemonIsLinux, MinimumAPIVersion("1.31"))
|
||||
dockerfile := `FROM busybox
|
||||
RUN echo 'test1:x:1001:1001::/bin:/bin/false' >> /etc/passwd
|
||||
RUN echo 'test1:x:1001:' >> /etc/group
|
||||
RUN echo 'test2:x:1002:' >> /etc/group
|
||||
COPY --chown=test1:1002 . /new_dir
|
||||
RUN ls -l /
|
||||
RUN [ $(ls -l / | grep new_dir | awk '{print $3":"$4}') = 'test1:test2' ]
|
||||
RUN [ $(ls -nl / | grep new_dir | awk '{print $3":"$4}') = '1001:1002' ]
|
||||
`
|
||||
ctx := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
fakecontext.WithFile("test_file1", "some test content"),
|
||||
)
|
||||
defer ctx.Close()
|
||||
|
||||
res, body, err := request.Post(
|
||||
"/build",
|
||||
request.RawContent(ctx.AsTarReader(c)),
|
||||
request.ContentType("application/x-tar"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
out, err := request.ReadBody(body)
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.Contains(string(out), "Successfully built"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildCopyCacheOnFileChange(c *check.C) {
|
||||
|
||||
dockerfile := `FROM busybox
|
||||
COPY file /file`
|
||||
|
||||
ctx1 := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
fakecontext.WithFile("file", "foo"))
|
||||
ctx2 := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
fakecontext.WithFile("file", "bar"))
|
||||
|
||||
var build = func(ctx *fakecontext.Fake) string {
|
||||
res, body, err := request.Post("/build",
|
||||
request.RawContent(ctx.AsTarReader(c)),
|
||||
request.ContentType("application/x-tar"))
|
||||
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.DeepEqual(http.StatusOK, res.StatusCode))
|
||||
|
||||
out, err := request.ReadBody(body)
|
||||
assert.NilError(c, err)
|
||||
|
||||
ids := getImageIDsFromBuild(c, out)
|
||||
return ids[len(ids)-1]
|
||||
}
|
||||
|
||||
id1 := build(ctx1)
|
||||
id2 := build(ctx1)
|
||||
id3 := build(ctx2)
|
||||
|
||||
if id1 != id2 {
|
||||
c.Fatal("didn't use the cache")
|
||||
}
|
||||
if id1 == id3 {
|
||||
c.Fatal("COPY With different source file should not share same cache")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildAddCacheOnFileChange(c *check.C) {
|
||||
|
||||
dockerfile := `FROM busybox
|
||||
ADD file /file`
|
||||
|
||||
ctx1 := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
fakecontext.WithFile("file", "foo"))
|
||||
ctx2 := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
fakecontext.WithFile("file", "bar"))
|
||||
|
||||
var build = func(ctx *fakecontext.Fake) string {
|
||||
res, body, err := request.Post("/build",
|
||||
request.RawContent(ctx.AsTarReader(c)),
|
||||
request.ContentType("application/x-tar"))
|
||||
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.DeepEqual(http.StatusOK, res.StatusCode))
|
||||
|
||||
out, err := request.ReadBody(body)
|
||||
assert.NilError(c, err)
|
||||
|
||||
ids := getImageIDsFromBuild(c, out)
|
||||
return ids[len(ids)-1]
|
||||
}
|
||||
|
||||
id1 := build(ctx1)
|
||||
id2 := build(ctx1)
|
||||
id3 := build(ctx2)
|
||||
|
||||
if id1 != id2 {
|
||||
c.Fatal("didn't use the cache")
|
||||
}
|
||||
if id1 == id3 {
|
||||
c.Fatal("COPY With different source file should not share same cache")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildScratchCopy(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerfile := `FROM scratch
|
||||
ADD Dockerfile /
|
||||
ENV foo bar`
|
||||
ctx := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
)
|
||||
defer ctx.Close()
|
||||
|
||||
res, body, err := request.Post(
|
||||
"/build",
|
||||
request.RawContent(ctx.AsTarReader(c)),
|
||||
request.ContentType("application/x-tar"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
out, err := request.ReadBody(body)
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.Contains(string(out), "Successfully built"))
|
||||
}
|
||||
|
||||
type buildLine struct {
|
||||
Stream string
|
||||
Aux struct {
|
||||
ID string
|
||||
}
|
||||
}
|
||||
|
||||
func getImageIDsFromBuild(c *check.C, output []byte) []string {
|
||||
var ids []string
|
||||
for _, line := range bytes.Split(output, []byte("\n")) {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
entry := buildLine{}
|
||||
assert.NilError(c, json.Unmarshal(line, &entry))
|
||||
if entry.Aux.ID != "" {
|
||||
ids = append(ids, entry.Aux.ID)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
39
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_build_windows_test.go
generated
vendored
Normal file
39
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_build_windows_test.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// +build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/fakecontext"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestBuildWithRecycleBin(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows)
|
||||
|
||||
dockerfile := "" +
|
||||
"FROM " + testEnv.PlatformDefaults.BaseImage + "\n" +
|
||||
"RUN md $REcycLE.biN && md missing\n" +
|
||||
"RUN dir $Recycle.Bin && exit 1 || exit 0\n" +
|
||||
"RUN dir missing\n"
|
||||
|
||||
ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile))
|
||||
defer ctx.Close()
|
||||
|
||||
res, body, err := request.Post(
|
||||
"/build",
|
||||
request.RawContent(ctx.AsTarReader(c)),
|
||||
request.ContentType("application/x-tar"))
|
||||
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
out, err := request.ReadBody(body)
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.Contains(string(out), "Successfully built"))
|
||||
}
|
2209
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_containers_test.go
generated
vendored
Normal file
2209
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_containers_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
76
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_containers_windows_test.go
generated
vendored
Normal file
76
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_containers_windows_test.go
generated
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
// +build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
winio "github.com/Microsoft/go-winio"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestContainersAPICreateMountsBindNamedPipe(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsWindowsAtLeastBuild(16299)) // Named pipe support was added in RS3
|
||||
|
||||
// Create a host pipe to map into the container
|
||||
hostPipeName := fmt.Sprintf(`\\.\pipe\docker-cli-test-pipe-%x`, rand.Uint64())
|
||||
pc := &winio.PipeConfig{
|
||||
SecurityDescriptor: "D:P(A;;GA;;;AU)", // Allow all users access to the pipe
|
||||
}
|
||||
l, err := winio.ListenPipe(hostPipeName, pc)
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// Asynchronously read data that the container writes to the mapped pipe.
|
||||
var b []byte
|
||||
ch := make(chan error)
|
||||
go func() {
|
||||
conn, err := l.Accept()
|
||||
if err == nil {
|
||||
b, err = ioutil.ReadAll(conn)
|
||||
conn.Close()
|
||||
}
|
||||
ch <- err
|
||||
}()
|
||||
|
||||
containerPipeName := `\\.\pipe\docker-cli-test-pipe`
|
||||
text := "hello from a pipe"
|
||||
cmd := fmt.Sprintf("echo %s > %s", text, containerPipeName)
|
||||
name := "test-bind-npipe"
|
||||
|
||||
ctx := context.Background()
|
||||
client := testEnv.APIClient()
|
||||
_, err = client.ContainerCreate(ctx,
|
||||
&container.Config{
|
||||
Image: testEnv.PlatformDefaults.BaseImage,
|
||||
Cmd: []string{"cmd", "/c", cmd},
|
||||
}, &container.HostConfig{
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: "npipe",
|
||||
Source: hostPipeName,
|
||||
Target: containerPipeName,
|
||||
},
|
||||
},
|
||||
},
|
||||
nil, name)
|
||||
assert.NilError(c, err)
|
||||
|
||||
err = client.ContainerStart(ctx, name, types.ContainerStartOptions{})
|
||||
assert.NilError(c, err)
|
||||
|
||||
err = <-ch
|
||||
assert.NilError(c, err)
|
||||
assert.Check(c, is.Equal(text, strings.TrimSpace(string(b))))
|
||||
}
|
136
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_create_test.go
generated
vendored
Normal file
136
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_create_test.go
generated
vendored
Normal file
|
@ -0,0 +1,136 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestAPICreateWithInvalidHealthcheckParams(c *check.C) {
|
||||
// test invalid Interval in Healthcheck: less than 0s
|
||||
name := "test1"
|
||||
config := map[string]interface{}{
|
||||
"Image": "busybox",
|
||||
"Healthcheck": map[string]interface{}{
|
||||
"Interval": -10 * time.Millisecond,
|
||||
"Timeout": time.Second,
|
||||
"Retries": int(1000),
|
||||
},
|
||||
}
|
||||
|
||||
res, body, err := request.Post("/containers/create?name="+name, request.JSONBody(config))
|
||||
c.Assert(err, check.IsNil)
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
buf, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
expected := fmt.Sprintf("Interval in Healthcheck cannot be less than %s", container.MinimumDuration)
|
||||
c.Assert(getErrorMessage(c, buf), checker.Contains, expected)
|
||||
|
||||
// test invalid Interval in Healthcheck: larger than 0s but less than 1ms
|
||||
name = "test2"
|
||||
config = map[string]interface{}{
|
||||
"Image": "busybox",
|
||||
"Healthcheck": map[string]interface{}{
|
||||
"Interval": 500 * time.Microsecond,
|
||||
"Timeout": time.Second,
|
||||
"Retries": int(1000),
|
||||
},
|
||||
}
|
||||
res, body, err = request.Post("/containers/create?name="+name, request.JSONBody(config))
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
buf, err = request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest)
|
||||
}
|
||||
c.Assert(getErrorMessage(c, buf), checker.Contains, expected)
|
||||
|
||||
// test invalid Timeout in Healthcheck: less than 1ms
|
||||
name = "test3"
|
||||
config = map[string]interface{}{
|
||||
"Image": "busybox",
|
||||
"Healthcheck": map[string]interface{}{
|
||||
"Interval": time.Second,
|
||||
"Timeout": -100 * time.Millisecond,
|
||||
"Retries": int(1000),
|
||||
},
|
||||
}
|
||||
res, body, err = request.Post("/containers/create?name="+name, request.JSONBody(config))
|
||||
c.Assert(err, check.IsNil)
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
buf, err = request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
expected = fmt.Sprintf("Timeout in Healthcheck cannot be less than %s", container.MinimumDuration)
|
||||
c.Assert(getErrorMessage(c, buf), checker.Contains, expected)
|
||||
|
||||
// test invalid Retries in Healthcheck: less than 0
|
||||
name = "test4"
|
||||
config = map[string]interface{}{
|
||||
"Image": "busybox",
|
||||
"Healthcheck": map[string]interface{}{
|
||||
"Interval": time.Second,
|
||||
"Timeout": time.Second,
|
||||
"Retries": int(-10),
|
||||
},
|
||||
}
|
||||
res, body, err = request.Post("/containers/create?name="+name, request.JSONBody(config))
|
||||
c.Assert(err, check.IsNil)
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
buf, err = request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
expected = "Retries in Healthcheck cannot be negative"
|
||||
c.Assert(getErrorMessage(c, buf), checker.Contains, expected)
|
||||
|
||||
// test invalid StartPeriod in Healthcheck: not 0 and less than 1ms
|
||||
name = "test3"
|
||||
config = map[string]interface{}{
|
||||
"Image": "busybox",
|
||||
"Healthcheck": map[string]interface{}{
|
||||
"Interval": time.Second,
|
||||
"Timeout": time.Second,
|
||||
"Retries": int(1000),
|
||||
"StartPeriod": 100 * time.Microsecond,
|
||||
},
|
||||
}
|
||||
res, body, err = request.Post("/containers/create?name="+name, request.JSONBody(config))
|
||||
c.Assert(err, check.IsNil)
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(res.StatusCode, check.Equals, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
buf, err = request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
expected = fmt.Sprintf("StartPeriod in Healthcheck cannot be less than %s", container.MinimumDuration)
|
||||
c.Assert(getErrorMessage(c, buf), checker.Contains, expected)
|
||||
}
|
113
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_exec_resize_test.go
generated
vendored
Normal file
113
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_exec_resize_test.go
generated
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestExecResizeAPIHeightWidthNoInt(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
endpoint := "/exec/" + cleanedContainerID + "/resize?h=foo&w=bar"
|
||||
res, _, err := request.Post(endpoint)
|
||||
c.Assert(err, checker.IsNil)
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
// Part of #14845
|
||||
func (s *DockerSuite) TestExecResizeImmediatelyAfterExecStart(c *check.C) {
|
||||
name := "exec_resize_test"
|
||||
dockerCmd(c, "run", "-d", "-i", "-t", "--name", name, "--restart", "always", "busybox", "/bin/sh")
|
||||
|
||||
testExecResize := func() error {
|
||||
data := map[string]interface{}{
|
||||
"AttachStdin": true,
|
||||
"Cmd": []string{"/bin/sh"},
|
||||
}
|
||||
uri := fmt.Sprintf("/containers/%s/exec", name)
|
||||
res, body, err := request.Post(uri, request.JSONBody(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
return fmt.Errorf("POST %s is expected to return %d, got %d", uri, http.StatusCreated, res.StatusCode)
|
||||
}
|
||||
|
||||
buf, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out := map[string]string{}
|
||||
err = json.Unmarshal(buf, &out)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ExecCreate returned invalid json. Error: %q", err.Error())
|
||||
}
|
||||
|
||||
execID := out["Id"]
|
||||
if len(execID) < 1 {
|
||||
return fmt.Errorf("ExecCreate got invalid execID")
|
||||
}
|
||||
|
||||
payload := bytes.NewBufferString(`{"Tty":true}`)
|
||||
conn, _, err := sockRequestHijack("POST", fmt.Sprintf("/exec/%s/start", execID), payload, "application/json", daemonHost())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to start the exec: %q", err.Error())
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
_, rc, err := request.Post(fmt.Sprintf("/exec/%s/resize?h=24&w=80", execID), request.ContentType("text/plain"))
|
||||
if err != nil {
|
||||
// It's probably a panic of the daemon if io.ErrUnexpectedEOF is returned.
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return fmt.Errorf("The daemon might have crashed.")
|
||||
}
|
||||
// Other error happened, should be reported.
|
||||
return fmt.Errorf("Fail to exec resize immediately after start. Error: %q", err.Error())
|
||||
}
|
||||
|
||||
rc.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The panic happens when daemon.ContainerExecStart is called but the
|
||||
// container.Exec is not called.
|
||||
// Because the panic is not 100% reproducible, we send the requests concurrently
|
||||
// to increase the probability that the problem is triggered.
|
||||
var (
|
||||
n = 10
|
||||
ch = make(chan error, n)
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
for i := 0; i < n; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := testExecResize(); err != nil {
|
||||
ch <- err
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
select {
|
||||
case err := <-ch:
|
||||
c.Fatal(err.Error())
|
||||
default:
|
||||
}
|
||||
}
|
313
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_exec_test.go
generated
vendored
Normal file
313
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_exec_test.go
generated
vendored
Normal file
|
@ -0,0 +1,313 @@
|
|||
// +build !test_no_exec
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// Regression test for #9414
|
||||
func (s *DockerSuite) TestExecAPICreateNoCmd(c *check.C) {
|
||||
name := "exec_test"
|
||||
dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
|
||||
|
||||
res, body, err := request.Post(fmt.Sprintf("/containers/%s/exec", name), request.JSONBody(map[string]interface{}{"Cmd": nil}))
|
||||
c.Assert(err, checker.IsNil)
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest)
|
||||
}
|
||||
b, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
comment := check.Commentf("Expected message when creating exec command with no Cmd specified")
|
||||
c.Assert(getErrorMessage(c, b), checker.Contains, "No exec command specified", comment)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecAPICreateNoValidContentType(c *check.C) {
|
||||
name := "exec_test"
|
||||
dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
|
||||
|
||||
jsonData := bytes.NewBuffer(nil)
|
||||
if err := json.NewEncoder(jsonData).Encode(map[string]interface{}{"Cmd": nil}); err != nil {
|
||||
c.Fatalf("Can not encode data to json %s", err)
|
||||
}
|
||||
|
||||
res, body, err := request.Post(fmt.Sprintf("/containers/%s/exec", name), request.RawContent(ioutil.NopCloser(jsonData)), request.ContentType("test/plain"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest)
|
||||
}
|
||||
b, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
comment := check.Commentf("Expected message when creating exec command with invalid Content-Type specified")
|
||||
c.Assert(getErrorMessage(c, b), checker.Contains, "Content-Type specified", comment)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecAPICreateContainerPaused(c *check.C) {
|
||||
// Not relevant on Windows as Windows containers cannot be paused
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "exec_create_test"
|
||||
dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
|
||||
|
||||
dockerCmd(c, "pause", name)
|
||||
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
config := types.ExecConfig{
|
||||
Cmd: []string{"true"},
|
||||
}
|
||||
_, err = cli.ContainerExecCreate(context.Background(), name, config)
|
||||
|
||||
comment := check.Commentf("Expected message when creating exec command with Container %s is paused", name)
|
||||
c.Assert(err.Error(), checker.Contains, "Container "+name+" is paused, unpause the container before exec", comment)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecAPIStart(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux) // Uses pause/unpause but bits may be salvageable to Windows to Windows CI
|
||||
dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
|
||||
|
||||
id := createExec(c, "test")
|
||||
startExec(c, id, http.StatusOK)
|
||||
|
||||
var execJSON struct{ PID int }
|
||||
inspectExec(c, id, &execJSON)
|
||||
c.Assert(execJSON.PID, checker.GreaterThan, 1)
|
||||
|
||||
id = createExec(c, "test")
|
||||
dockerCmd(c, "stop", "test")
|
||||
|
||||
startExec(c, id, http.StatusNotFound)
|
||||
|
||||
dockerCmd(c, "start", "test")
|
||||
startExec(c, id, http.StatusNotFound)
|
||||
|
||||
// make sure exec is created before pausing
|
||||
id = createExec(c, "test")
|
||||
dockerCmd(c, "pause", "test")
|
||||
startExec(c, id, http.StatusConflict)
|
||||
dockerCmd(c, "unpause", "test")
|
||||
startExec(c, id, http.StatusOK)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecAPIStartEnsureHeaders(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
|
||||
|
||||
id := createExec(c, "test")
|
||||
resp, _, err := request.Post(fmt.Sprintf("/exec/%s/start", id), request.RawString(`{"Detach": true}`), request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.Header.Get("Server"), checker.Not(checker.Equals), "")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecAPIStartBackwardsCompatible(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux) // Windows only supports 1.25 or later
|
||||
runSleepingContainer(c, "-d", "--name", "test")
|
||||
id := createExec(c, "test")
|
||||
|
||||
resp, body, err := request.Post(fmt.Sprintf("/v1.20/exec/%s/start", id), request.RawString(`{"Detach": true}`), request.ContentType("text/plain"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
b, err := request.ReadBody(body)
|
||||
comment := check.Commentf("response body: %s", b)
|
||||
c.Assert(err, checker.IsNil, comment)
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK, comment)
|
||||
}
|
||||
|
||||
// #19362
|
||||
func (s *DockerSuite) TestExecAPIStartMultipleTimesError(c *check.C) {
|
||||
runSleepingContainer(c, "-d", "--name", "test")
|
||||
execID := createExec(c, "test")
|
||||
startExec(c, execID, http.StatusOK)
|
||||
waitForExec(c, execID)
|
||||
|
||||
startExec(c, execID, http.StatusConflict)
|
||||
}
|
||||
|
||||
// #20638
|
||||
func (s *DockerSuite) TestExecAPIStartWithDetach(c *check.C) {
|
||||
name := "foo"
|
||||
runSleepingContainer(c, "-d", "-t", "--name", name)
|
||||
|
||||
config := types.ExecConfig{
|
||||
Cmd: []string{"true"},
|
||||
AttachStderr: true,
|
||||
}
|
||||
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
createResp, err := cli.ContainerExecCreate(context.Background(), name, config)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, body, err := request.Post(fmt.Sprintf("/exec/%s/start", createResp.ID), request.RawString(`{"Detach": true}`), request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
b, err := request.ReadBody(body)
|
||||
comment := check.Commentf("response body: %s", b)
|
||||
c.Assert(err, checker.IsNil, comment)
|
||||
|
||||
resp, _, err := request.Get("/_ping")
|
||||
c.Assert(err, checker.IsNil)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
c.Fatal("daemon is down, it should alive")
|
||||
}
|
||||
}
|
||||
|
||||
// #30311
|
||||
func (s *DockerSuite) TestExecAPIStartValidCommand(c *check.C) {
|
||||
name := "exec_test"
|
||||
dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
|
||||
|
||||
id := createExecCmd(c, name, "true")
|
||||
startExec(c, id, http.StatusOK)
|
||||
|
||||
waitForExec(c, id)
|
||||
|
||||
var inspectJSON struct{ ExecIDs []string }
|
||||
inspectContainer(c, name, &inspectJSON)
|
||||
|
||||
c.Assert(inspectJSON.ExecIDs, checker.IsNil)
|
||||
}
|
||||
|
||||
// #30311
|
||||
func (s *DockerSuite) TestExecAPIStartInvalidCommand(c *check.C) {
|
||||
name := "exec_test"
|
||||
dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
|
||||
|
||||
id := createExecCmd(c, name, "invalid")
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
startExec(c, id, http.StatusNotFound)
|
||||
} else {
|
||||
startExec(c, id, http.StatusBadRequest)
|
||||
}
|
||||
waitForExec(c, id)
|
||||
|
||||
var inspectJSON struct{ ExecIDs []string }
|
||||
inspectContainer(c, name, &inspectJSON)
|
||||
|
||||
c.Assert(inspectJSON.ExecIDs, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecStateCleanup(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
|
||||
// This test checks accidental regressions. Not part of stable API.
|
||||
|
||||
name := "exec_cleanup"
|
||||
cid, _ := dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
|
||||
cid = strings.TrimSpace(cid)
|
||||
|
||||
stateDir := "/var/run/docker/containerd/" + cid
|
||||
|
||||
checkReadDir := func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
fi, err := ioutil.ReadDir(stateDir)
|
||||
c.Assert(err, checker.IsNil)
|
||||
return len(fi), nil
|
||||
}
|
||||
|
||||
fi, err := ioutil.ReadDir(stateDir)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(len(fi), checker.GreaterThan, 1)
|
||||
|
||||
id := createExecCmd(c, name, "ls")
|
||||
startExec(c, id, http.StatusOK)
|
||||
waitForExec(c, id)
|
||||
|
||||
waitAndAssert(c, 5*time.Second, checkReadDir, checker.Equals, len(fi))
|
||||
|
||||
id = createExecCmd(c, name, "invalid")
|
||||
startExec(c, id, http.StatusBadRequest)
|
||||
waitForExec(c, id)
|
||||
|
||||
waitAndAssert(c, 5*time.Second, checkReadDir, checker.Equals, len(fi))
|
||||
|
||||
dockerCmd(c, "stop", name)
|
||||
_, err = os.Stat(stateDir)
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(os.IsNotExist(err), checker.True)
|
||||
}
|
||||
|
||||
func createExec(c *check.C, name string) string {
|
||||
return createExecCmd(c, name, "true")
|
||||
}
|
||||
|
||||
func createExecCmd(c *check.C, name string, cmd string) string {
|
||||
_, reader, err := request.Post(fmt.Sprintf("/containers/%s/exec", name), request.JSONBody(map[string]interface{}{"Cmd": []string{cmd}}))
|
||||
c.Assert(err, checker.IsNil)
|
||||
b, err := ioutil.ReadAll(reader)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer reader.Close()
|
||||
createResp := struct {
|
||||
ID string `json:"Id"`
|
||||
}{}
|
||||
c.Assert(json.Unmarshal(b, &createResp), checker.IsNil, check.Commentf(string(b)))
|
||||
return createResp.ID
|
||||
}
|
||||
|
||||
func startExec(c *check.C, id string, code int) {
|
||||
resp, body, err := request.Post(fmt.Sprintf("/exec/%s/start", id), request.RawString(`{"Detach": true}`), request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
b, err := request.ReadBody(body)
|
||||
comment := check.Commentf("response body: %s", b)
|
||||
c.Assert(err, checker.IsNil, comment)
|
||||
c.Assert(resp.StatusCode, checker.Equals, code, comment)
|
||||
}
|
||||
|
||||
func inspectExec(c *check.C, id string, out interface{}) {
|
||||
resp, body, err := request.Get(fmt.Sprintf("/exec/%s/json", id))
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer body.Close()
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
|
||||
err = json.NewDecoder(body).Decode(out)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func waitForExec(c *check.C, id string) {
|
||||
timeout := time.After(60 * time.Second)
|
||||
var execJSON struct{ Running bool }
|
||||
for {
|
||||
select {
|
||||
case <-timeout:
|
||||
c.Fatal("timeout waiting for exec to start")
|
||||
default:
|
||||
}
|
||||
|
||||
inspectExec(c, id, &execJSON)
|
||||
if !execJSON.Running {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func inspectContainer(c *check.C, id string, out interface{}) {
|
||||
resp, body, err := request.Get(fmt.Sprintf("/containers/%s/json", id))
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer body.Close()
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
|
||||
err = json.NewDecoder(body).Decode(out)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
208
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_images_test.go
generated
vendored
Normal file
208
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_images_test.go
generated
vendored
Normal file
|
@ -0,0 +1,208 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestAPIImagesFilter(c *check.C) {
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
name := "utest:tag1"
|
||||
name2 := "utest/docker:tag2"
|
||||
name3 := "utest:5000/docker:tag3"
|
||||
for _, n := range []string{name, name2, name3} {
|
||||
dockerCmd(c, "tag", "busybox", n)
|
||||
}
|
||||
getImages := func(filter string) []types.ImageSummary {
|
||||
filters := filters.NewArgs()
|
||||
filters.Add("reference", filter)
|
||||
options := types.ImageListOptions{
|
||||
All: false,
|
||||
Filters: filters,
|
||||
}
|
||||
images, err := cli.ImageList(context.Background(), options)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
return images
|
||||
}
|
||||
|
||||
//incorrect number of matches returned
|
||||
images := getImages("utest*/*")
|
||||
c.Assert(images[0].RepoTags, checker.HasLen, 2)
|
||||
|
||||
images = getImages("utest")
|
||||
c.Assert(images[0].RepoTags, checker.HasLen, 1)
|
||||
|
||||
images = getImages("utest*")
|
||||
c.Assert(images[0].RepoTags, checker.HasLen, 1)
|
||||
|
||||
images = getImages("*5000*/*")
|
||||
c.Assert(images[0].RepoTags, checker.HasLen, 1)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIImagesSaveAndLoad(c *check.C) {
|
||||
if runtime.GOOS == "windows" {
|
||||
v, err := kernel.GetKernelVersion()
|
||||
c.Assert(err, checker.IsNil)
|
||||
build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0])
|
||||
if build == 16299 {
|
||||
c.Skip("Temporarily disabled on RS3 builds")
|
||||
}
|
||||
}
|
||||
|
||||
testRequires(c, Network)
|
||||
buildImageSuccessfully(c, "saveandload", build.WithDockerfile("FROM busybox\nENV FOO bar"))
|
||||
id := getIDByName(c, "saveandload")
|
||||
|
||||
res, body, err := request.Get("/images/" + id + "/get")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer body.Close()
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
dockerCmd(c, "rmi", id)
|
||||
|
||||
res, loadBody, err := request.Post("/images/load", request.RawContent(body), request.ContentType("application/x-tar"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer loadBody.Close()
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
inspectOut := cli.InspectCmd(c, id, cli.Format(".Id")).Combined()
|
||||
c.Assert(strings.TrimSpace(string(inspectOut)), checker.Equals, id, check.Commentf("load did not work properly"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIImagesDelete(c *check.C) {
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
if testEnv.OSType != "windows" {
|
||||
testRequires(c, Network)
|
||||
}
|
||||
name := "test-api-images-delete"
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENV FOO bar"))
|
||||
id := getIDByName(c, name)
|
||||
|
||||
dockerCmd(c, "tag", name, "test:tag1")
|
||||
|
||||
_, err = cli.ImageRemove(context.Background(), id, types.ImageRemoveOptions{})
|
||||
c.Assert(err.Error(), checker.Contains, "unable to delete")
|
||||
|
||||
_, err = cli.ImageRemove(context.Background(), "test:noexist", types.ImageRemoveOptions{})
|
||||
c.Assert(err.Error(), checker.Contains, "No such image")
|
||||
|
||||
_, err = cli.ImageRemove(context.Background(), "test:tag1", types.ImageRemoveOptions{})
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIImagesHistory(c *check.C) {
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
if testEnv.OSType != "windows" {
|
||||
testRequires(c, Network)
|
||||
}
|
||||
name := "test-api-images-history"
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENV FOO bar"))
|
||||
id := getIDByName(c, name)
|
||||
|
||||
historydata, err := cli.ImageHistory(context.Background(), id)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(historydata, checker.Not(checker.HasLen), 0)
|
||||
var found bool
|
||||
for _, tag := range historydata[0].Tags {
|
||||
if tag == "test-api-images-history:latest" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
c.Assert(found, checker.True)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIImagesImportBadSrc(c *check.C) {
|
||||
if runtime.GOOS == "windows" {
|
||||
v, err := kernel.GetKernelVersion()
|
||||
c.Assert(err, checker.IsNil)
|
||||
build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0])
|
||||
if build == 16299 {
|
||||
c.Skip("Temporarily disabled on RS3 builds")
|
||||
}
|
||||
}
|
||||
|
||||
testRequires(c, Network, SameHostDaemon)
|
||||
|
||||
server := httptest.NewServer(http.NewServeMux())
|
||||
defer server.Close()
|
||||
|
||||
tt := []struct {
|
||||
statusExp int
|
||||
fromSrc string
|
||||
}{
|
||||
{http.StatusNotFound, server.URL + "/nofile.tar"},
|
||||
{http.StatusNotFound, strings.TrimPrefix(server.URL, "http://") + "/nofile.tar"},
|
||||
{http.StatusNotFound, strings.TrimPrefix(server.URL, "http://") + "%2Fdata%2Ffile.tar"},
|
||||
{http.StatusInternalServerError, "%2Fdata%2Ffile.tar"},
|
||||
}
|
||||
|
||||
for _, te := range tt {
|
||||
res, _, err := request.Post(strings.Join([]string{"/images/create?fromSrc=", te.fromSrc}, ""), request.JSON)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, te.statusExp)
|
||||
c.Assert(res.Header.Get("Content-Type"), checker.Equals, "application/json")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// #14846
|
||||
func (s *DockerSuite) TestAPIImagesSearchJSONContentType(c *check.C) {
|
||||
testRequires(c, Network)
|
||||
|
||||
res, b, err := request.Get("/images/search?term=test", request.JSON)
|
||||
c.Assert(err, check.IsNil)
|
||||
b.Close()
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
c.Assert(res.Header.Get("Content-Type"), checker.Equals, "application/json")
|
||||
}
|
||||
|
||||
// Test case for 30027: image size reported as -1 in v1.12 client against v1.13 daemon.
|
||||
// This test checks to make sure both v1.12 and v1.13 client against v1.13 daemon get correct `Size` after the fix.
|
||||
func (s *DockerSuite) TestAPIImagesSizeCompatibility(c *check.C) {
|
||||
apiclient := testEnv.APIClient()
|
||||
defer apiclient.Close()
|
||||
|
||||
images, err := apiclient.ImageList(context.Background(), types.ImageListOptions{})
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(len(images), checker.Not(checker.Equals), 0)
|
||||
for _, image := range images {
|
||||
c.Assert(image.Size, checker.Not(checker.Equals), int64(-1))
|
||||
}
|
||||
|
||||
apiclient, err = client.NewClientWithOpts(client.FromEnv, client.WithVersion("v1.24"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer apiclient.Close()
|
||||
|
||||
v124Images, err := apiclient.ImageList(context.Background(), types.ImageListOptions{})
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(len(v124Images), checker.Not(checker.Equals), 0)
|
||||
for _, image := range v124Images {
|
||||
c.Assert(image.Size, checker.Not(checker.Equals), int64(-1))
|
||||
}
|
||||
}
|
181
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_inspect_test.go
generated
vendored
Normal file
181
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_inspect_test.go
generated
vendored
Normal file
|
@ -0,0 +1,181 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions/v1p20"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestInspectAPIContainerResponse(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
keysBase := []string{"Id", "State", "Created", "Path", "Args", "Config", "Image", "NetworkSettings",
|
||||
"ResolvConfPath", "HostnamePath", "HostsPath", "LogPath", "Name", "Driver", "MountLabel", "ProcessLabel", "GraphDriver"}
|
||||
|
||||
type acase struct {
|
||||
version string
|
||||
keys []string
|
||||
}
|
||||
|
||||
var cases []acase
|
||||
|
||||
if testEnv.OSType == "windows" {
|
||||
cases = []acase{
|
||||
{"v1.25", append(keysBase, "Mounts")},
|
||||
}
|
||||
|
||||
} else {
|
||||
cases = []acase{
|
||||
{"v1.20", append(keysBase, "Mounts")},
|
||||
{"v1.19", append(keysBase, "Volumes", "VolumesRW")},
|
||||
}
|
||||
}
|
||||
|
||||
for _, cs := range cases {
|
||||
body := getInspectBody(c, cs.version, cleanedContainerID)
|
||||
|
||||
var inspectJSON map[string]interface{}
|
||||
err := json.Unmarshal(body, &inspectJSON)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Unable to unmarshal body for version %s", cs.version))
|
||||
|
||||
for _, key := range cs.keys {
|
||||
_, ok := inspectJSON[key]
|
||||
c.Check(ok, checker.True, check.Commentf("%s does not exist in response for version %s", key, cs.version))
|
||||
}
|
||||
|
||||
//Issue #6830: type not properly converted to JSON/back
|
||||
_, ok := inspectJSON["Path"].(bool)
|
||||
c.Assert(ok, checker.False, check.Commentf("Path of `true` should not be converted to boolean `true` via JSON marshalling"))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectAPIContainerVolumeDriverLegacy(c *check.C) {
|
||||
// No legacy implications for Windows
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
cases := []string{"v1.19", "v1.20"}
|
||||
for _, version := range cases {
|
||||
body := getInspectBody(c, version, cleanedContainerID)
|
||||
|
||||
var inspectJSON map[string]interface{}
|
||||
err := json.Unmarshal(body, &inspectJSON)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Unable to unmarshal body for version %s", version))
|
||||
|
||||
config, ok := inspectJSON["Config"]
|
||||
c.Assert(ok, checker.True, check.Commentf("Unable to find 'Config'"))
|
||||
cfg := config.(map[string]interface{})
|
||||
_, ok = cfg["VolumeDriver"]
|
||||
c.Assert(ok, checker.True, check.Commentf("API version %s expected to include VolumeDriver in 'Config'", version))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectAPIContainerVolumeDriver(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "--volume-driver", "local", "busybox", "true")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
body := getInspectBody(c, "v1.25", cleanedContainerID)
|
||||
|
||||
var inspectJSON map[string]interface{}
|
||||
err := json.Unmarshal(body, &inspectJSON)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Unable to unmarshal body for version 1.25"))
|
||||
|
||||
config, ok := inspectJSON["Config"]
|
||||
c.Assert(ok, checker.True, check.Commentf("Unable to find 'Config'"))
|
||||
cfg := config.(map[string]interface{})
|
||||
_, ok = cfg["VolumeDriver"]
|
||||
c.Assert(ok, checker.False, check.Commentf("API version 1.25 expected to not include VolumeDriver in 'Config'"))
|
||||
|
||||
config, ok = inspectJSON["HostConfig"]
|
||||
c.Assert(ok, checker.True, check.Commentf("Unable to find 'HostConfig'"))
|
||||
cfg = config.(map[string]interface{})
|
||||
_, ok = cfg["VolumeDriver"]
|
||||
c.Assert(ok, checker.True, check.Commentf("API version 1.25 expected to include VolumeDriver in 'HostConfig'"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectAPIImageResponse(c *check.C) {
|
||||
dockerCmd(c, "tag", "busybox:latest", "busybox:mytag")
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
imageJSON, _, err := cli.ImageInspectWithRaw(context.Background(), "busybox")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(imageJSON.RepoTags, checker.HasLen, 2)
|
||||
assert.Check(c, is.Contains(imageJSON.RepoTags, "busybox:latest"))
|
||||
assert.Check(c, is.Contains(imageJSON.RepoTags, "busybox:mytag"))
|
||||
}
|
||||
|
||||
// #17131, #17139, #17173
|
||||
func (s *DockerSuite) TestInspectAPIEmptyFieldsInConfigPre121(c *check.C) {
|
||||
// Not relevant on Windows
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
cases := []string{"v1.19", "v1.20"}
|
||||
for _, version := range cases {
|
||||
body := getInspectBody(c, version, cleanedContainerID)
|
||||
|
||||
var inspectJSON map[string]interface{}
|
||||
err := json.Unmarshal(body, &inspectJSON)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Unable to unmarshal body for version %s", version))
|
||||
config, ok := inspectJSON["Config"]
|
||||
c.Assert(ok, checker.True, check.Commentf("Unable to find 'Config'"))
|
||||
cfg := config.(map[string]interface{})
|
||||
for _, f := range []string{"MacAddress", "NetworkDisabled", "ExposedPorts"} {
|
||||
_, ok := cfg[f]
|
||||
c.Check(ok, checker.True, check.Commentf("API version %s expected to include %s in 'Config'", version, f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectAPIBridgeNetworkSettings120(c *check.C) {
|
||||
// Not relevant on Windows, and besides it doesn't have any bridge network settings
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
containerID := strings.TrimSpace(out)
|
||||
waitRun(containerID)
|
||||
|
||||
body := getInspectBody(c, "v1.20", containerID)
|
||||
|
||||
var inspectJSON v1p20.ContainerJSON
|
||||
err := json.Unmarshal(body, &inspectJSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
settings := inspectJSON.NetworkSettings
|
||||
c.Assert(settings.IPAddress, checker.Not(checker.HasLen), 0)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectAPIBridgeNetworkSettings121(c *check.C) {
|
||||
// Windows doesn't have any bridge network settings
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
containerID := strings.TrimSpace(out)
|
||||
waitRun(containerID)
|
||||
|
||||
body := getInspectBody(c, "v1.21", containerID)
|
||||
|
||||
var inspectJSON types.ContainerJSON
|
||||
err := json.Unmarshal(body, &inspectJSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
settings := inspectJSON.NetworkSettings
|
||||
c.Assert(settings.IPAddress, checker.Not(checker.HasLen), 0)
|
||||
c.Assert(settings.Networks["bridge"], checker.Not(checker.IsNil))
|
||||
c.Assert(settings.IPAddress, checker.Equals, settings.Networks["bridge"].IPAddress)
|
||||
}
|
81
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_ipcmode_test.go
generated
vendored
Normal file
81
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_ipcmode_test.go
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
// build +linux
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
/* 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()
|
||||
}
|
||||
|
||||
/* TestAPIIpcModeHost checks that a container created with --ipc host
|
||||
* can use IPC of the host system.
|
||||
*/
|
||||
func (s *DockerSuite) TestAPIIpcModeHost(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace)
|
||||
|
||||
cfg := container.Config{
|
||||
Image: "busybox",
|
||||
Cmd: []string{"top"},
|
||||
}
|
||||
hostCfg := container.HostConfig{
|
||||
IpcMode: container.IpcMode("host"),
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
client := testEnv.APIClient()
|
||||
resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(len(resp.Warnings), checker.Equals, 0)
|
||||
name := resp.ID
|
||||
|
||||
err = client.ContainerStart(ctx, name, types.ContainerStartOptions{})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// check that IPC is shared
|
||||
// 1. create a file inside container
|
||||
cli.DockerCmd(c, "exec", name, "sh", "-c", "printf covfefe > /dev/shm/."+name)
|
||||
// 2. check it's the same on the host
|
||||
bytes, err := ioutil.ReadFile("/dev/shm/." + name)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(bytes), checker.Matches, "^covfefe$")
|
||||
// 3. clean up
|
||||
cli.DockerCmd(c, "exec", name, "rm", "-f", "/dev/shm/."+name)
|
||||
}
|
216
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_logs_test.go
generated
vendored
Normal file
216
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_logs_test.go
generated
vendored
Normal file
|
@ -0,0 +1,216 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestLogsAPIWithStdout(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "-t", "busybox", "/bin/sh", "-c", "while true; do echo hello; sleep 1; done")
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), checker.IsNil)
|
||||
|
||||
type logOut struct {
|
||||
out string
|
||||
err error
|
||||
}
|
||||
|
||||
chLog := make(chan logOut)
|
||||
res, body, err := request.Get(fmt.Sprintf("/containers/%s/logs?follow=1&stdout=1×tamps=1", id))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
go func() {
|
||||
defer body.Close()
|
||||
out, err := bufio.NewReader(body).ReadString('\n')
|
||||
if err != nil {
|
||||
chLog <- logOut{"", err}
|
||||
return
|
||||
}
|
||||
chLog <- logOut{strings.TrimSpace(out), err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case l := <-chLog:
|
||||
c.Assert(l.err, checker.IsNil)
|
||||
if !strings.HasSuffix(l.out, "hello") {
|
||||
c.Fatalf("expected log output to container 'hello', but it does not")
|
||||
}
|
||||
case <-time.After(30 * time.Second):
|
||||
c.Fatal("timeout waiting for logs to exit")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsAPINoStdoutNorStderr(c *check.C) {
|
||||
name := "logs_test"
|
||||
dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerLogs(context.Background(), name, types.ContainerLogsOptions{})
|
||||
expected := "Bad parameters: you must choose at least one stream"
|
||||
c.Assert(err.Error(), checker.Contains, expected)
|
||||
}
|
||||
|
||||
// Regression test for #12704
|
||||
func (s *DockerSuite) TestLogsAPIFollowEmptyOutput(c *check.C) {
|
||||
name := "logs_test"
|
||||
t0 := time.Now()
|
||||
dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "sleep", "10")
|
||||
|
||||
_, body, err := request.Get(fmt.Sprintf("/containers/%s/logs?follow=1&stdout=1&stderr=1&tail=all", name))
|
||||
t1 := time.Now()
|
||||
c.Assert(err, checker.IsNil)
|
||||
body.Close()
|
||||
elapsed := t1.Sub(t0).Seconds()
|
||||
if elapsed > 20.0 {
|
||||
c.Fatalf("HTTP response was not immediate (elapsed %.1fs)", elapsed)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsAPIContainerNotFound(c *check.C) {
|
||||
name := "nonExistentContainer"
|
||||
resp, _, err := request.Get(fmt.Sprintf("/containers/%s/logs?follow=1&stdout=1&stderr=1&tail=all", name))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsAPIUntilFutureFollow(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "logsuntilfuturefollow"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "busybox", "/bin/sh", "-c", "while true; do date +%s; sleep 1; done")
|
||||
c.Assert(waitRun(name), checker.IsNil)
|
||||
|
||||
untilSecs := 5
|
||||
untilDur, err := time.ParseDuration(fmt.Sprintf("%ds", untilSecs))
|
||||
c.Assert(err, checker.IsNil)
|
||||
until := daemonTime(c).Add(untilDur)
|
||||
|
||||
client, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
cfg := types.ContainerLogsOptions{Until: until.Format(time.RFC3339Nano), Follow: true, ShowStdout: true, Timestamps: true}
|
||||
reader, err := client.ContainerLogs(context.Background(), name, cfg)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
type logOut struct {
|
||||
out string
|
||||
err error
|
||||
}
|
||||
|
||||
chLog := make(chan logOut)
|
||||
|
||||
go func() {
|
||||
bufReader := bufio.NewReader(reader)
|
||||
defer reader.Close()
|
||||
for i := 0; i < untilSecs; i++ {
|
||||
out, _, err := bufReader.ReadLine()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
chLog <- logOut{"", err}
|
||||
return
|
||||
}
|
||||
|
||||
chLog <- logOut{strings.TrimSpace(string(out)), err}
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < untilSecs; i++ {
|
||||
select {
|
||||
case l := <-chLog:
|
||||
c.Assert(l.err, checker.IsNil)
|
||||
i, err := strconv.ParseInt(strings.Split(l.out, " ")[1], 10, 64)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(time.Unix(i, 0).UnixNano(), checker.LessOrEqualThan, until.UnixNano())
|
||||
case <-time.After(20 * time.Second):
|
||||
c.Fatal("timeout waiting for logs to exit")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsAPIUntil(c *check.C) {
|
||||
testRequires(c, MinimumAPIVersion("1.34"))
|
||||
name := "logsuntil"
|
||||
dockerCmd(c, "run", "--name", name, "busybox", "/bin/sh", "-c", "for i in $(seq 1 3); do echo log$i; sleep 1; done")
|
||||
|
||||
client, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
extractBody := func(c *check.C, cfg types.ContainerLogsOptions) []string {
|
||||
reader, err := client.ContainerLogs(context.Background(), name, cfg)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
actualStdout := new(bytes.Buffer)
|
||||
actualStderr := ioutil.Discard
|
||||
_, err = stdcopy.StdCopy(actualStdout, actualStderr, reader)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
return strings.Split(actualStdout.String(), "\n")
|
||||
}
|
||||
|
||||
// Get timestamp of second log line
|
||||
allLogs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true})
|
||||
c.Assert(len(allLogs), checker.GreaterOrEqualThan, 3)
|
||||
|
||||
t, err := time.Parse(time.RFC3339Nano, strings.Split(allLogs[1], " ")[0])
|
||||
c.Assert(err, checker.IsNil)
|
||||
until := t.Format(time.RFC3339Nano)
|
||||
|
||||
// Get logs until the timestamp of second line, i.e. first two lines
|
||||
logs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true, Until: until})
|
||||
|
||||
// Ensure log lines after cut-off are excluded
|
||||
logsString := strings.Join(logs, "\n")
|
||||
c.Assert(logsString, checker.Not(checker.Contains), "log3", check.Commentf("unexpected log message returned, until=%v", until))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsAPIUntilDefaultValue(c *check.C) {
|
||||
name := "logsuntildefaultval"
|
||||
dockerCmd(c, "run", "--name", name, "busybox", "/bin/sh", "-c", "for i in $(seq 1 3); do echo log$i; done")
|
||||
|
||||
client, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
extractBody := func(c *check.C, cfg types.ContainerLogsOptions) []string {
|
||||
reader, err := client.ContainerLogs(context.Background(), name, cfg)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
actualStdout := new(bytes.Buffer)
|
||||
actualStderr := ioutil.Discard
|
||||
_, err = stdcopy.StdCopy(actualStdout, actualStderr, reader)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
return strings.Split(actualStdout.String(), "\n")
|
||||
}
|
||||
|
||||
// Get timestamp of second log line
|
||||
allLogs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true})
|
||||
|
||||
// Test with default value specified and parameter omitted
|
||||
defaultLogs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true, Until: "0"})
|
||||
c.Assert(defaultLogs, checker.DeepEquals, allLogs)
|
||||
}
|
376
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_network_test.go
generated
vendored
Normal file
376
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_network_test.go
generated
vendored
Normal file
|
@ -0,0 +1,376 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestAPINetworkGetDefaults(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// By default docker daemon creates 3 networks. check if they are present
|
||||
defaults := []string{"bridge", "host", "none"}
|
||||
for _, nn := range defaults {
|
||||
c.Assert(isNetworkAvailable(c, nn), checker.Equals, true)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPINetworkCreateCheckDuplicate(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "testcheckduplicate"
|
||||
configOnCheck := types.NetworkCreateRequest{
|
||||
Name: name,
|
||||
NetworkCreate: types.NetworkCreate{
|
||||
CheckDuplicate: true,
|
||||
},
|
||||
}
|
||||
configNotCheck := types.NetworkCreateRequest{
|
||||
Name: name,
|
||||
NetworkCreate: types.NetworkCreate{
|
||||
CheckDuplicate: false,
|
||||
},
|
||||
}
|
||||
|
||||
// Creating a new network first
|
||||
createNetwork(c, configOnCheck, http.StatusCreated)
|
||||
c.Assert(isNetworkAvailable(c, name), checker.Equals, true)
|
||||
|
||||
// Creating another network with same name and CheckDuplicate must fail
|
||||
isOlderAPI := versions.LessThan(testEnv.DaemonAPIVersion(), "1.34")
|
||||
expectedStatus := http.StatusConflict
|
||||
if isOlderAPI {
|
||||
// In the early test code it uses bool value to represent
|
||||
// whether createNetwork() is expected to fail or not.
|
||||
// Therefore, we use negation to handle the same logic after
|
||||
// the code was changed in https://github.com/moby/moby/pull/35030
|
||||
// -http.StatusCreated will also be checked as NOT equal to
|
||||
// http.StatusCreated in createNetwork() function.
|
||||
expectedStatus = -http.StatusCreated
|
||||
}
|
||||
createNetwork(c, configOnCheck, expectedStatus)
|
||||
|
||||
// Creating another network with same name and not CheckDuplicate must succeed
|
||||
createNetwork(c, configNotCheck, http.StatusCreated)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPINetworkFilter(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
nr := getNetworkResource(c, getNetworkIDByName(c, "bridge"))
|
||||
c.Assert(nr.Name, checker.Equals, "bridge")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPINetworkInspectBridge(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// Inspect default bridge network
|
||||
nr := getNetworkResource(c, "bridge")
|
||||
c.Assert(nr.Name, checker.Equals, "bridge")
|
||||
|
||||
// run a container and attach it to the default bridge network
|
||||
out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
|
||||
containerID := strings.TrimSpace(out)
|
||||
containerIP := findContainerIP(c, "test", "bridge")
|
||||
|
||||
// inspect default bridge network again and make sure the container is connected
|
||||
nr = getNetworkResource(c, nr.ID)
|
||||
c.Assert(nr.Driver, checker.Equals, "bridge")
|
||||
c.Assert(nr.Scope, checker.Equals, "local")
|
||||
c.Assert(nr.Internal, checker.Equals, false)
|
||||
c.Assert(nr.EnableIPv6, checker.Equals, false)
|
||||
c.Assert(nr.IPAM.Driver, checker.Equals, "default")
|
||||
c.Assert(nr.Containers[containerID], checker.NotNil)
|
||||
|
||||
ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(ip.String(), checker.Equals, containerIP)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPINetworkInspectUserDefinedNetwork(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// IPAM configuration inspect
|
||||
ipam := &network.IPAM{
|
||||
Driver: "default",
|
||||
Config: []network.IPAMConfig{{Subnet: "172.28.0.0/16", IPRange: "172.28.5.0/24", Gateway: "172.28.5.254"}},
|
||||
}
|
||||
config := types.NetworkCreateRequest{
|
||||
Name: "br0",
|
||||
NetworkCreate: types.NetworkCreate{
|
||||
Driver: "bridge",
|
||||
IPAM: ipam,
|
||||
Options: map[string]string{"foo": "bar", "opts": "dopts"},
|
||||
},
|
||||
}
|
||||
id0 := createNetwork(c, config, http.StatusCreated)
|
||||
c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, true)
|
||||
|
||||
nr := getNetworkResource(c, id0)
|
||||
c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
|
||||
c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16")
|
||||
c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24")
|
||||
c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254")
|
||||
c.Assert(nr.Options["foo"], checker.Equals, "bar")
|
||||
c.Assert(nr.Options["opts"], checker.Equals, "dopts")
|
||||
|
||||
// delete the network and make sure it is deleted
|
||||
deleteNetwork(c, id0, true)
|
||||
c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, false)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPINetworkConnectDisconnect(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// Create test network
|
||||
name := "testnetwork"
|
||||
config := types.NetworkCreateRequest{
|
||||
Name: name,
|
||||
}
|
||||
id := createNetwork(c, config, http.StatusCreated)
|
||||
nr := getNetworkResource(c, id)
|
||||
c.Assert(nr.Name, checker.Equals, name)
|
||||
c.Assert(nr.ID, checker.Equals, id)
|
||||
c.Assert(len(nr.Containers), checker.Equals, 0)
|
||||
|
||||
// run a container
|
||||
out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
// connect the container to the test network
|
||||
connectNetwork(c, nr.ID, containerID)
|
||||
|
||||
// inspect the network to make sure container is connected
|
||||
nr = getNetworkResource(c, nr.ID)
|
||||
c.Assert(len(nr.Containers), checker.Equals, 1)
|
||||
c.Assert(nr.Containers[containerID], checker.NotNil)
|
||||
|
||||
// check if container IP matches network inspect
|
||||
ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
|
||||
c.Assert(err, checker.IsNil)
|
||||
containerIP := findContainerIP(c, "test", "testnetwork")
|
||||
c.Assert(ip.String(), checker.Equals, containerIP)
|
||||
|
||||
// disconnect container from the network
|
||||
disconnectNetwork(c, nr.ID, containerID)
|
||||
nr = getNetworkResource(c, nr.ID)
|
||||
c.Assert(nr.Name, checker.Equals, name)
|
||||
c.Assert(len(nr.Containers), checker.Equals, 0)
|
||||
|
||||
// delete the network
|
||||
deleteNetwork(c, nr.ID, true)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPINetworkIPAMMultipleBridgeNetworks(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// test0 bridge network
|
||||
ipam0 := &network.IPAM{
|
||||
Driver: "default",
|
||||
Config: []network.IPAMConfig{{Subnet: "192.178.0.0/16", IPRange: "192.178.128.0/17", Gateway: "192.178.138.100"}},
|
||||
}
|
||||
config0 := types.NetworkCreateRequest{
|
||||
Name: "test0",
|
||||
NetworkCreate: types.NetworkCreate{
|
||||
Driver: "bridge",
|
||||
IPAM: ipam0,
|
||||
},
|
||||
}
|
||||
id0 := createNetwork(c, config0, http.StatusCreated)
|
||||
c.Assert(isNetworkAvailable(c, "test0"), checker.Equals, true)
|
||||
|
||||
ipam1 := &network.IPAM{
|
||||
Driver: "default",
|
||||
Config: []network.IPAMConfig{{Subnet: "192.178.128.0/17", Gateway: "192.178.128.1"}},
|
||||
}
|
||||
// test1 bridge network overlaps with test0
|
||||
config1 := types.NetworkCreateRequest{
|
||||
Name: "test1",
|
||||
NetworkCreate: types.NetworkCreate{
|
||||
Driver: "bridge",
|
||||
IPAM: ipam1,
|
||||
},
|
||||
}
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
createNetwork(c, config1, http.StatusInternalServerError)
|
||||
} else {
|
||||
createNetwork(c, config1, http.StatusForbidden)
|
||||
}
|
||||
c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, false)
|
||||
|
||||
ipam2 := &network.IPAM{
|
||||
Driver: "default",
|
||||
Config: []network.IPAMConfig{{Subnet: "192.169.0.0/16", Gateway: "192.169.100.100"}},
|
||||
}
|
||||
// test2 bridge network does not overlap
|
||||
config2 := types.NetworkCreateRequest{
|
||||
Name: "test2",
|
||||
NetworkCreate: types.NetworkCreate{
|
||||
Driver: "bridge",
|
||||
IPAM: ipam2,
|
||||
},
|
||||
}
|
||||
createNetwork(c, config2, http.StatusCreated)
|
||||
c.Assert(isNetworkAvailable(c, "test2"), checker.Equals, true)
|
||||
|
||||
// remove test0 and retry to create test1
|
||||
deleteNetwork(c, id0, true)
|
||||
createNetwork(c, config1, http.StatusCreated)
|
||||
c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, true)
|
||||
|
||||
// for networks w/o ipam specified, docker will choose proper non-overlapping subnets
|
||||
createNetwork(c, types.NetworkCreateRequest{Name: "test3"}, http.StatusCreated)
|
||||
c.Assert(isNetworkAvailable(c, "test3"), checker.Equals, true)
|
||||
createNetwork(c, types.NetworkCreateRequest{Name: "test4"}, http.StatusCreated)
|
||||
c.Assert(isNetworkAvailable(c, "test4"), checker.Equals, true)
|
||||
createNetwork(c, types.NetworkCreateRequest{Name: "test5"}, http.StatusCreated)
|
||||
c.Assert(isNetworkAvailable(c, "test5"), checker.Equals, true)
|
||||
|
||||
for i := 1; i < 6; i++ {
|
||||
deleteNetwork(c, fmt.Sprintf("test%d", i), true)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPICreateDeletePredefinedNetworks(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SwarmInactive)
|
||||
createDeletePredefinedNetwork(c, "bridge")
|
||||
createDeletePredefinedNetwork(c, "none")
|
||||
createDeletePredefinedNetwork(c, "host")
|
||||
}
|
||||
|
||||
func createDeletePredefinedNetwork(c *check.C, name string) {
|
||||
// Create pre-defined network
|
||||
config := types.NetworkCreateRequest{
|
||||
Name: name,
|
||||
NetworkCreate: types.NetworkCreate{
|
||||
CheckDuplicate: true,
|
||||
},
|
||||
}
|
||||
expectedStatus := http.StatusForbidden
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.34") {
|
||||
// In the early test code it uses bool value to represent
|
||||
// whether createNetwork() is expected to fail or not.
|
||||
// Therefore, we use negation to handle the same logic after
|
||||
// the code was changed in https://github.com/moby/moby/pull/35030
|
||||
// -http.StatusCreated will also be checked as NOT equal to
|
||||
// http.StatusCreated in createNetwork() function.
|
||||
expectedStatus = -http.StatusCreated
|
||||
}
|
||||
createNetwork(c, config, expectedStatus)
|
||||
deleteNetwork(c, name, false)
|
||||
}
|
||||
|
||||
func isNetworkAvailable(c *check.C, name string) bool {
|
||||
resp, body, err := request.Get("/networks")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer resp.Body.Close()
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
|
||||
|
||||
var nJSON []types.NetworkResource
|
||||
err = json.NewDecoder(body).Decode(&nJSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
for _, n := range nJSON {
|
||||
if n.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getNetworkIDByName(c *check.C, name string) string {
|
||||
var (
|
||||
v = url.Values{}
|
||||
filterArgs = filters.NewArgs()
|
||||
)
|
||||
filterArgs.Add("name", name)
|
||||
filterJSON, err := filters.ToJSON(filterArgs)
|
||||
c.Assert(err, checker.IsNil)
|
||||
v.Set("filters", filterJSON)
|
||||
|
||||
resp, body, err := request.Get("/networks?" + v.Encode())
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var nJSON []types.NetworkResource
|
||||
err = json.NewDecoder(body).Decode(&nJSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
var res string
|
||||
for _, n := range nJSON {
|
||||
// Find exact match
|
||||
if n.Name == name {
|
||||
res = n.ID
|
||||
}
|
||||
}
|
||||
c.Assert(res, checker.Not(checker.Equals), "")
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func getNetworkResource(c *check.C, id string) *types.NetworkResource {
|
||||
_, obj, err := request.Get("/networks/" + id)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
nr := types.NetworkResource{}
|
||||
err = json.NewDecoder(obj).Decode(&nr)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
return &nr
|
||||
}
|
||||
|
||||
func createNetwork(c *check.C, config types.NetworkCreateRequest, expectedStatusCode int) string {
|
||||
resp, body, err := request.Post("/networks/create", request.JSONBody(config))
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer resp.Body.Close()
|
||||
|
||||
if expectedStatusCode >= 0 {
|
||||
c.Assert(resp.StatusCode, checker.Equals, expectedStatusCode)
|
||||
} else {
|
||||
c.Assert(resp.StatusCode, checker.Not(checker.Equals), -expectedStatusCode)
|
||||
}
|
||||
|
||||
if expectedStatusCode == http.StatusCreated || expectedStatusCode < 0 {
|
||||
var nr types.NetworkCreateResponse
|
||||
err = json.NewDecoder(body).Decode(&nr)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
return nr.ID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func connectNetwork(c *check.C, nid, cid string) {
|
||||
config := types.NetworkConnect{
|
||||
Container: cid,
|
||||
}
|
||||
|
||||
resp, _, err := request.Post("/networks/"+nid+"/connect", request.JSONBody(config))
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func disconnectNetwork(c *check.C, nid, cid string) {
|
||||
config := types.NetworkConnect{
|
||||
Container: cid,
|
||||
}
|
||||
|
||||
resp, _, err := request.Post("/networks/"+nid+"/disconnect", request.JSONBody(config))
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func deleteNetwork(c *check.C, id string, shouldSucceed bool) {
|
||||
resp, _, err := request.Delete("/networks/" + id)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer resp.Body.Close()
|
||||
if !shouldSucceed {
|
||||
c.Assert(resp.StatusCode, checker.Not(checker.Equals), http.StatusOK)
|
||||
return
|
||||
}
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusNoContent)
|
||||
}
|
314
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_stats_test.go
generated
vendored
Normal file
314
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_stats_test.go
generated
vendored
Normal file
|
@ -0,0 +1,314 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
var expectedNetworkInterfaceStats = strings.Split("rx_bytes rx_dropped rx_errors rx_packets tx_bytes tx_dropped tx_errors tx_packets", " ")
|
||||
|
||||
func (s *DockerSuite) TestAPIStatsNoStreamGetCpu(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true;usleep 100; do echo 'Hello'; done")
|
||||
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), checker.IsNil)
|
||||
resp, body, err := request.Get(fmt.Sprintf("/containers/%s/stats?stream=false", id))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
|
||||
c.Assert(resp.Header.Get("Content-Type"), checker.Equals, "application/json")
|
||||
|
||||
var v *types.Stats
|
||||
err = json.NewDecoder(body).Decode(&v)
|
||||
c.Assert(err, checker.IsNil)
|
||||
body.Close()
|
||||
|
||||
var cpuPercent = 0.0
|
||||
|
||||
if testEnv.OSType != "windows" {
|
||||
cpuDelta := float64(v.CPUStats.CPUUsage.TotalUsage - v.PreCPUStats.CPUUsage.TotalUsage)
|
||||
systemDelta := float64(v.CPUStats.SystemUsage - v.PreCPUStats.SystemUsage)
|
||||
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CPUStats.CPUUsage.PercpuUsage)) * 100.0
|
||||
} else {
|
||||
// Max number of 100ns intervals between the previous time read and now
|
||||
possIntervals := uint64(v.Read.Sub(v.PreRead).Nanoseconds()) // Start with number of ns intervals
|
||||
possIntervals /= 100 // Convert to number of 100ns intervals
|
||||
possIntervals *= uint64(v.NumProcs) // Multiple by the number of processors
|
||||
|
||||
// Intervals used
|
||||
intervalsUsed := v.CPUStats.CPUUsage.TotalUsage - v.PreCPUStats.CPUUsage.TotalUsage
|
||||
|
||||
// Percentage avoiding divide-by-zero
|
||||
if possIntervals > 0 {
|
||||
cpuPercent = float64(intervalsUsed) / float64(possIntervals) * 100.0
|
||||
}
|
||||
}
|
||||
|
||||
c.Assert(cpuPercent, check.Not(checker.Equals), 0.0, check.Commentf("docker stats with no-stream get cpu usage failed: was %v", cpuPercent))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIStatsStoppedContainerInGoroutines(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo 1")
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
getGoRoutines := func() int {
|
||||
_, body, err := request.Get(fmt.Sprintf("/info"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
info := types.Info{}
|
||||
err = json.NewDecoder(body).Decode(&info)
|
||||
c.Assert(err, checker.IsNil)
|
||||
body.Close()
|
||||
return info.NGoroutines
|
||||
}
|
||||
|
||||
// When the HTTP connection is closed, the number of goroutines should not increase.
|
||||
routines := getGoRoutines()
|
||||
_, body, err := request.Get(fmt.Sprintf("/containers/%s/stats", id))
|
||||
c.Assert(err, checker.IsNil)
|
||||
body.Close()
|
||||
|
||||
t := time.After(30 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-t:
|
||||
c.Assert(getGoRoutines(), checker.LessOrEqualThan, routines)
|
||||
return
|
||||
default:
|
||||
if n := getGoRoutines(); n <= routines {
|
||||
return
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIStatsNetworkStats(c *check.C) {
|
||||
testRequires(c, SameHostDaemon)
|
||||
|
||||
out := runSleepingContainer(c)
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), checker.IsNil)
|
||||
|
||||
// Retrieve the container address
|
||||
net := "bridge"
|
||||
if testEnv.OSType == "windows" {
|
||||
net = "nat"
|
||||
}
|
||||
contIP := findContainerIP(c, id, net)
|
||||
numPings := 1
|
||||
|
||||
var preRxPackets uint64
|
||||
var preTxPackets uint64
|
||||
var postRxPackets uint64
|
||||
var postTxPackets uint64
|
||||
|
||||
// Get the container networking stats before and after pinging the container
|
||||
nwStatsPre := getNetworkStats(c, id)
|
||||
for _, v := range nwStatsPre {
|
||||
preRxPackets += v.RxPackets
|
||||
preTxPackets += v.TxPackets
|
||||
}
|
||||
|
||||
countParam := "-c"
|
||||
if runtime.GOOS == "windows" {
|
||||
countParam = "-n" // Ping count parameter is -n on Windows
|
||||
}
|
||||
pingout, err := exec.Command("ping", contIP, countParam, strconv.Itoa(numPings)).CombinedOutput()
|
||||
if err != nil && runtime.GOOS == "linux" {
|
||||
// If it fails then try a work-around, but just for linux.
|
||||
// If this fails too then go back to the old error for reporting.
|
||||
//
|
||||
// The ping will sometimes fail due to an apparmor issue where it
|
||||
// denies access to the libc.so.6 shared library - running it
|
||||
// via /lib64/ld-linux-x86-64.so.2 seems to work around it.
|
||||
pingout2, err2 := exec.Command("/lib64/ld-linux-x86-64.so.2", "/bin/ping", contIP, "-c", strconv.Itoa(numPings)).CombinedOutput()
|
||||
if err2 == nil {
|
||||
pingout = pingout2
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
c.Assert(err, checker.IsNil)
|
||||
pingouts := string(pingout[:])
|
||||
nwStatsPost := getNetworkStats(c, id)
|
||||
for _, v := range nwStatsPost {
|
||||
postRxPackets += v.RxPackets
|
||||
postTxPackets += v.TxPackets
|
||||
}
|
||||
|
||||
// Verify the stats contain at least the expected number of packets
|
||||
// On Linux, account for ARP.
|
||||
expRxPkts := preRxPackets + uint64(numPings)
|
||||
expTxPkts := preTxPackets + uint64(numPings)
|
||||
if testEnv.OSType != "windows" {
|
||||
expRxPkts++
|
||||
expTxPkts++
|
||||
}
|
||||
c.Assert(postTxPackets, checker.GreaterOrEqualThan, expTxPkts,
|
||||
check.Commentf("Reported less TxPackets than expected. Expected >= %d. Found %d. %s", expTxPkts, postTxPackets, pingouts))
|
||||
c.Assert(postRxPackets, checker.GreaterOrEqualThan, expRxPkts,
|
||||
check.Commentf("Reported less RxPackets than expected. Expected >= %d. Found %d. %s", expRxPkts, postRxPackets, pingouts))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIStatsNetworkStatsVersioning(c *check.C) {
|
||||
// Windows doesn't support API versions less than 1.25, so no point testing 1.17 .. 1.21
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
out := runSleepingContainer(c)
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), checker.IsNil)
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
for i := 17; i <= 21; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
apiVersion := fmt.Sprintf("v1.%d", i)
|
||||
statsJSONBlob := getVersionedStats(c, id, apiVersion)
|
||||
if versions.LessThan(apiVersion, "v1.21") {
|
||||
c.Assert(jsonBlobHasLTv121NetworkStats(statsJSONBlob), checker.Equals, true,
|
||||
check.Commentf("Stats JSON blob from API %s %#v does not look like a <v1.21 API stats structure", apiVersion, statsJSONBlob))
|
||||
} else {
|
||||
c.Assert(jsonBlobHasGTE121NetworkStats(statsJSONBlob), checker.Equals, true,
|
||||
check.Commentf("Stats JSON blob from API %s %#v does not look like a >=v1.21 API stats structure", apiVersion, statsJSONBlob))
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func getNetworkStats(c *check.C, id string) map[string]types.NetworkStats {
|
||||
var st *types.StatsJSON
|
||||
|
||||
_, body, err := request.Get(fmt.Sprintf("/containers/%s/stats?stream=false", id))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = json.NewDecoder(body).Decode(&st)
|
||||
c.Assert(err, checker.IsNil)
|
||||
body.Close()
|
||||
|
||||
return st.Networks
|
||||
}
|
||||
|
||||
// getVersionedStats returns stats result for the
|
||||
// container with id using an API call with version apiVersion. Since the
|
||||
// stats result type differs between API versions, we simply return
|
||||
// map[string]interface{}.
|
||||
func getVersionedStats(c *check.C, id string, apiVersion string) map[string]interface{} {
|
||||
stats := make(map[string]interface{})
|
||||
|
||||
_, body, err := request.Get(fmt.Sprintf("/%s/containers/%s/stats?stream=false", apiVersion, id))
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer body.Close()
|
||||
|
||||
err = json.NewDecoder(body).Decode(&stats)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to decode stat: %s", err))
|
||||
|
||||
return stats
|
||||
}
|
||||
|
||||
func jsonBlobHasLTv121NetworkStats(blob map[string]interface{}) bool {
|
||||
networkStatsIntfc, ok := blob["network"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
networkStats, ok := networkStatsIntfc.(map[string]interface{})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, expectedKey := range expectedNetworkInterfaceStats {
|
||||
if _, ok := networkStats[expectedKey]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func jsonBlobHasGTE121NetworkStats(blob map[string]interface{}) bool {
|
||||
networksStatsIntfc, ok := blob["networks"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
networksStats, ok := networksStatsIntfc.(map[string]interface{})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, networkInterfaceStatsIntfc := range networksStats {
|
||||
networkInterfaceStats, ok := networkInterfaceStatsIntfc.(map[string]interface{})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, expectedKey := range expectedNetworkInterfaceStats {
|
||||
if _, ok := networkInterfaceStats[expectedKey]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIStatsContainerNotFound(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
expected := "No such container: nonexistent"
|
||||
|
||||
_, err = cli.ContainerStats(context.Background(), "nonexistent", true)
|
||||
c.Assert(err.Error(), checker.Contains, expected)
|
||||
_, err = cli.ContainerStats(context.Background(), "nonexistent", false)
|
||||
c.Assert(err.Error(), checker.Contains, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIStatsNoStreamConnectedContainers(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out1 := runSleepingContainer(c)
|
||||
id1 := strings.TrimSpace(out1)
|
||||
c.Assert(waitRun(id1), checker.IsNil)
|
||||
|
||||
out2 := runSleepingContainer(c, "--net", "container:"+id1)
|
||||
id2 := strings.TrimSpace(out2)
|
||||
c.Assert(waitRun(id2), checker.IsNil)
|
||||
|
||||
ch := make(chan error, 1)
|
||||
go func() {
|
||||
resp, body, err := request.Get(fmt.Sprintf("/containers/%s/stats?stream=false", id2))
|
||||
defer body.Close()
|
||||
if err != nil {
|
||||
ch <- err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
ch <- fmt.Errorf("Invalid StatusCode %v", resp.StatusCode)
|
||||
}
|
||||
if resp.Header.Get("Content-Type") != "application/json" {
|
||||
ch <- fmt.Errorf("Invalid 'Content-Type' %v", resp.Header.Get("Content-Type"))
|
||||
}
|
||||
var v *types.Stats
|
||||
if err := json.NewDecoder(body).Decode(&v); err != nil {
|
||||
ch <- err
|
||||
}
|
||||
ch <- nil
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-ch:
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Error in stats Engine API: %v", err))
|
||||
case <-time.After(15 * time.Second):
|
||||
c.Fatalf("Stats did not return after timeout")
|
||||
}
|
||||
}
|
127
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_swarm_node_test.go
generated
vendored
Normal file
127
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_swarm_node_test.go
generated
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmListNodes(c *check.C) {
|
||||
d1 := s.AddDaemon(c, true, true)
|
||||
d2 := s.AddDaemon(c, true, false)
|
||||
d3 := s.AddDaemon(c, true, false)
|
||||
|
||||
nodes := d1.ListNodes(c)
|
||||
c.Assert(len(nodes), checker.Equals, 3, check.Commentf("nodes: %#v", nodes))
|
||||
|
||||
loop0:
|
||||
for _, n := range nodes {
|
||||
for _, d := range []*daemon.Daemon{d1, d2, d3} {
|
||||
if n.ID == d.NodeID() {
|
||||
continue loop0
|
||||
}
|
||||
}
|
||||
c.Errorf("unknown nodeID %v", n.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmNodeUpdate(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
nodes := d.ListNodes(c)
|
||||
|
||||
d.UpdateNode(c, nodes[0].ID, func(n *swarm.Node) {
|
||||
n.Spec.Availability = swarm.NodeAvailabilityPause
|
||||
})
|
||||
|
||||
n := d.GetNode(c, nodes[0].ID)
|
||||
c.Assert(n.Spec.Availability, checker.Equals, swarm.NodeAvailabilityPause)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmNodeRemove(c *check.C) {
|
||||
testRequires(c, Network)
|
||||
d1 := s.AddDaemon(c, true, true)
|
||||
d2 := s.AddDaemon(c, true, false)
|
||||
_ = s.AddDaemon(c, true, false)
|
||||
|
||||
nodes := d1.ListNodes(c)
|
||||
c.Assert(len(nodes), checker.Equals, 3, check.Commentf("nodes: %#v", nodes))
|
||||
|
||||
// Getting the info so we can take the NodeID
|
||||
d2Info := d2.SwarmInfo(c)
|
||||
|
||||
// forceful removal of d2 should work
|
||||
d1.RemoveNode(c, d2Info.NodeID, true)
|
||||
|
||||
nodes = d1.ListNodes(c)
|
||||
c.Assert(len(nodes), checker.Equals, 2, check.Commentf("nodes: %#v", nodes))
|
||||
|
||||
// Restart the node that was removed
|
||||
d2.Restart(c)
|
||||
|
||||
// Give some time for the node to rejoin
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Make sure the node didn't rejoin
|
||||
nodes = d1.ListNodes(c)
|
||||
c.Assert(len(nodes), checker.Equals, 2, check.Commentf("nodes: %#v", nodes))
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmNodeDrainPause(c *check.C) {
|
||||
d1 := s.AddDaemon(c, true, true)
|
||||
d2 := s.AddDaemon(c, true, false)
|
||||
|
||||
time.Sleep(1 * time.Second) // make sure all daemons are ready to accept tasks
|
||||
|
||||
// start a service, expect balanced distribution
|
||||
instances := 8
|
||||
id := d1.CreateService(c, simpleTestService, setInstances(instances))
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.GreaterThan, 0)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.GreaterThan, 0)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount), checker.Equals, instances)
|
||||
|
||||
// drain d2, all containers should move to d1
|
||||
d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
|
||||
n.Spec.Availability = swarm.NodeAvailabilityDrain
|
||||
})
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, instances)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.Equals, 0)
|
||||
|
||||
// set d2 back to active
|
||||
d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
|
||||
n.Spec.Availability = swarm.NodeAvailabilityActive
|
||||
})
|
||||
|
||||
instances = 1
|
||||
d1.UpdateService(c, d1.GetService(c, id), setInstances(instances))
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout*2, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount), checker.Equals, instances)
|
||||
|
||||
instances = 8
|
||||
d1.UpdateService(c, d1.GetService(c, id), setInstances(instances))
|
||||
|
||||
// drained node first so we don't get any old containers
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.GreaterThan, 0)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.GreaterThan, 0)
|
||||
waitAndAssert(c, defaultReconciliationTimeout*2, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount), checker.Equals, instances)
|
||||
|
||||
d2ContainerCount := len(d2.ActiveContainers(c))
|
||||
|
||||
// set d2 to paused, scale service up, only d1 gets new tasks
|
||||
d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
|
||||
n.Spec.Availability = swarm.NodeAvailabilityPause
|
||||
})
|
||||
|
||||
instances = 14
|
||||
d1.UpdateService(c, d1.GetService(c, id), setInstances(instances))
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, instances-d2ContainerCount)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.Equals, d2ContainerCount)
|
||||
|
||||
}
|
612
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_swarm_service_test.go
generated
vendored
Normal file
612
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_swarm_service_test.go
generated
vendored
Normal file
|
@ -0,0 +1,612 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
testdaemon "github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/go-check/check"
|
||||
"golang.org/x/sys/unix"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func setPortConfig(portConfig []swarm.PortConfig) testdaemon.ServiceConstructor {
|
||||
return func(s *swarm.Service) {
|
||||
if s.Spec.EndpointSpec == nil {
|
||||
s.Spec.EndpointSpec = &swarm.EndpointSpec{}
|
||||
}
|
||||
s.Spec.EndpointSpec.Ports = portConfig
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPIServiceUpdatePort(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
// Create a service with a port mapping of 8080:8081.
|
||||
portConfig := []swarm.PortConfig{{TargetPort: 8081, PublishedPort: 8080}}
|
||||
serviceID := d.CreateService(c, simpleTestService, setInstances(1), setPortConfig(portConfig))
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
|
||||
|
||||
// Update the service: changed the port mapping from 8080:8081 to 8082:8083.
|
||||
updatedPortConfig := []swarm.PortConfig{{TargetPort: 8083, PublishedPort: 8082}}
|
||||
remoteService := d.GetService(c, serviceID)
|
||||
d.UpdateService(c, remoteService, setPortConfig(updatedPortConfig))
|
||||
|
||||
// Inspect the service and verify port mapping.
|
||||
updatedService := d.GetService(c, serviceID)
|
||||
c.Assert(updatedService.Spec.EndpointSpec, check.NotNil)
|
||||
c.Assert(len(updatedService.Spec.EndpointSpec.Ports), check.Equals, 1)
|
||||
c.Assert(updatedService.Spec.EndpointSpec.Ports[0].TargetPort, check.Equals, uint32(8083))
|
||||
c.Assert(updatedService.Spec.EndpointSpec.Ports[0].PublishedPort, check.Equals, uint32(8082))
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicesEmptyList(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
services := d.ListServices(c)
|
||||
c.Assert(services, checker.NotNil)
|
||||
c.Assert(len(services), checker.Equals, 0, check.Commentf("services: %#v", services))
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicesCreate(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
instances := 2
|
||||
id := d.CreateService(c, simpleTestService, setInstances(instances))
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances)
|
||||
|
||||
cli, err := d.NewClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
options := types.ServiceInspectOptions{InsertDefaults: true}
|
||||
|
||||
// insertDefaults inserts UpdateConfig when service is fetched by ID
|
||||
resp, _, err := cli.ServiceInspectWithRaw(context.Background(), id, options)
|
||||
out := fmt.Sprintf("%+v", resp)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, "UpdateConfig")
|
||||
|
||||
// insertDefaults inserts UpdateConfig when service is fetched by ID
|
||||
resp, _, err = cli.ServiceInspectWithRaw(context.Background(), "top", options)
|
||||
out = fmt.Sprintf("%+v", resp)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(out), checker.Contains, "UpdateConfig")
|
||||
|
||||
service := d.GetService(c, id)
|
||||
instances = 5
|
||||
d.UpdateService(c, service, setInstances(instances))
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances)
|
||||
|
||||
d.RemoveService(c, service.ID)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 0)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicesMultipleAgents(c *check.C) {
|
||||
d1 := s.AddDaemon(c, true, true)
|
||||
d2 := s.AddDaemon(c, true, false)
|
||||
d3 := s.AddDaemon(c, true, false)
|
||||
|
||||
time.Sleep(1 * time.Second) // make sure all daemons are ready to accept tasks
|
||||
|
||||
instances := 9
|
||||
id := d1.CreateService(c, simpleTestService, setInstances(instances))
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.GreaterThan, 0)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.GreaterThan, 0)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d3.CheckActiveContainerCount, checker.GreaterThan, 0)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
|
||||
|
||||
// reconciliation on d2 node down
|
||||
d2.Stop(c)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
|
||||
|
||||
// test downscaling
|
||||
instances = 5
|
||||
d1.UpdateService(c, d1.GetService(c, id), setInstances(instances))
|
||||
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicesCreateGlobal(c *check.C) {
|
||||
d1 := s.AddDaemon(c, true, true)
|
||||
d2 := s.AddDaemon(c, true, false)
|
||||
d3 := s.AddDaemon(c, true, false)
|
||||
|
||||
d1.CreateService(c, simpleTestService, setGlobalMode)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, 1)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.Equals, 1)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d3.CheckActiveContainerCount, checker.Equals, 1)
|
||||
|
||||
d4 := s.AddDaemon(c, true, false)
|
||||
d5 := s.AddDaemon(c, true, false)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d4.CheckActiveContainerCount, checker.Equals, 1)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d5.CheckActiveContainerCount, checker.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicesUpdate(c *check.C) {
|
||||
const nodeCount = 3
|
||||
var daemons [nodeCount]*daemon.Daemon
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
daemons[i] = s.AddDaemon(c, true, i == 0)
|
||||
}
|
||||
// wait for nodes ready
|
||||
waitAndAssert(c, 5*time.Second, daemons[0].CheckNodeReadyCount, checker.Equals, nodeCount)
|
||||
|
||||
// service image at start
|
||||
image1 := "busybox:latest"
|
||||
// target image in update
|
||||
image2 := "busybox:test"
|
||||
|
||||
// create a different tag
|
||||
for _, d := range daemons {
|
||||
out, err := d.Cmd("tag", image1, image2)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
// create service
|
||||
instances := 5
|
||||
parallelism := 2
|
||||
rollbackParallelism := 3
|
||||
id := daemons[0].CreateService(c, serviceForUpdate, setInstances(instances))
|
||||
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances})
|
||||
|
||||
// issue service update
|
||||
service := daemons[0].GetService(c, id)
|
||||
daemons[0].UpdateService(c, service, setImage(image2))
|
||||
|
||||
// first batch
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances - parallelism, image2: parallelism})
|
||||
|
||||
// 2nd batch
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances - 2*parallelism, image2: 2 * parallelism})
|
||||
|
||||
// 3nd batch
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image2: instances})
|
||||
|
||||
// Roll back to the previous version. This uses the CLI because
|
||||
// rollback used to be a client-side operation.
|
||||
out, err := daemons[0].Cmd("service", "update", "--detach", "--rollback", id)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
// first batch
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image2: instances - rollbackParallelism, image1: rollbackParallelism})
|
||||
|
||||
// 2nd batch
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances})
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateStartFirst(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
// service image at start
|
||||
image1 := "busybox:latest"
|
||||
// target image in update
|
||||
image2 := "testhealth:latest"
|
||||
|
||||
// service started from this image won't pass health check
|
||||
result := cli.BuildCmd(c, image2, cli.Daemon(d),
|
||||
build.WithDockerfile(`FROM busybox
|
||||
HEALTHCHECK --interval=1s --timeout=30s --retries=1024 \
|
||||
CMD cat /status`),
|
||||
)
|
||||
result.Assert(c, icmd.Success)
|
||||
|
||||
// create service
|
||||
instances := 5
|
||||
parallelism := 2
|
||||
rollbackParallelism := 3
|
||||
id := d.CreateService(c, serviceForUpdate, setInstances(instances), setUpdateOrder(swarm.UpdateOrderStartFirst), setRollbackOrder(swarm.UpdateOrderStartFirst))
|
||||
|
||||
checkStartingTasks := func(expected int) []swarm.Task {
|
||||
var startingTasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks := d.GetServiceTasks(c, id)
|
||||
startingTasks = nil
|
||||
for _, t := range tasks {
|
||||
if t.Status.State == swarm.TaskStateStarting {
|
||||
startingTasks = append(startingTasks, t)
|
||||
}
|
||||
}
|
||||
return startingTasks, nil
|
||||
}, checker.HasLen, expected)
|
||||
|
||||
return startingTasks
|
||||
}
|
||||
|
||||
makeTasksHealthy := func(tasks []swarm.Task) {
|
||||
for _, t := range tasks {
|
||||
containerID := t.Status.ContainerStatus.ContainerID
|
||||
d.Cmd("exec", containerID, "touch", "/status")
|
||||
}
|
||||
}
|
||||
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances})
|
||||
|
||||
// issue service update
|
||||
service := d.GetService(c, id)
|
||||
d.UpdateService(c, service, setImage(image2))
|
||||
|
||||
// first batch
|
||||
|
||||
// The old tasks should be running, and the new ones should be starting.
|
||||
startingTasks := checkStartingTasks(parallelism)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances})
|
||||
|
||||
// make it healthy
|
||||
makeTasksHealthy(startingTasks)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances - parallelism, image2: parallelism})
|
||||
|
||||
// 2nd batch
|
||||
|
||||
// The old tasks should be running, and the new ones should be starting.
|
||||
startingTasks = checkStartingTasks(parallelism)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances - parallelism, image2: parallelism})
|
||||
|
||||
// make it healthy
|
||||
makeTasksHealthy(startingTasks)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances - 2*parallelism, image2: 2 * parallelism})
|
||||
|
||||
// 3nd batch
|
||||
|
||||
// The old tasks should be running, and the new ones should be starting.
|
||||
startingTasks = checkStartingTasks(1)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances - 2*parallelism, image2: 2 * parallelism})
|
||||
|
||||
// make it healthy
|
||||
makeTasksHealthy(startingTasks)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image2: instances})
|
||||
|
||||
// Roll back to the previous version. This uses the CLI because
|
||||
// rollback is a client-side operation.
|
||||
out, err := d.Cmd("service", "update", "--detach", "--rollback", id)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
// first batch
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image2: instances - rollbackParallelism, image1: rollbackParallelism})
|
||||
|
||||
// 2nd batch
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances})
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicesFailedUpdate(c *check.C) {
|
||||
const nodeCount = 3
|
||||
var daemons [nodeCount]*daemon.Daemon
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
daemons[i] = s.AddDaemon(c, true, i == 0)
|
||||
}
|
||||
// wait for nodes ready
|
||||
waitAndAssert(c, 5*time.Second, daemons[0].CheckNodeReadyCount, checker.Equals, nodeCount)
|
||||
|
||||
// service image at start
|
||||
image1 := "busybox:latest"
|
||||
// target image in update
|
||||
image2 := "busybox:badtag"
|
||||
|
||||
// create service
|
||||
instances := 5
|
||||
id := daemons[0].CreateService(c, serviceForUpdate, setInstances(instances))
|
||||
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances})
|
||||
|
||||
// issue service update
|
||||
service := daemons[0].GetService(c, id)
|
||||
daemons[0].UpdateService(c, service, setImage(image2), setFailureAction(swarm.UpdateFailureActionPause), setMaxFailureRatio(0.25), setParallelism(1))
|
||||
|
||||
// should update 2 tasks and then pause
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceUpdateState(id), checker.Equals, swarm.UpdateStatePaused)
|
||||
v, _ := daemons[0].CheckServiceRunningTasks(id)(c)
|
||||
c.Assert(v, checker.Equals, instances-2)
|
||||
|
||||
// Roll back to the previous version. This uses the CLI because
|
||||
// rollback used to be a client-side operation.
|
||||
out, err := daemons[0].Cmd("service", "update", "--detach", "--rollback", id)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances})
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintRole(c *check.C) {
|
||||
const nodeCount = 3
|
||||
var daemons [nodeCount]*daemon.Daemon
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
daemons[i] = s.AddDaemon(c, true, i == 0)
|
||||
}
|
||||
// wait for nodes ready
|
||||
waitAndAssert(c, 5*time.Second, daemons[0].CheckNodeReadyCount, checker.Equals, nodeCount)
|
||||
|
||||
// create service
|
||||
constraints := []string{"node.role==worker"}
|
||||
instances := 3
|
||||
id := daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
|
||||
// validate tasks are running on worker nodes
|
||||
tasks := daemons[0].GetServiceTasks(c, id)
|
||||
for _, task := range tasks {
|
||||
node := daemons[0].GetNode(c, task.NodeID)
|
||||
c.Assert(node.Spec.Role, checker.Equals, swarm.NodeRoleWorker)
|
||||
}
|
||||
//remove service
|
||||
daemons[0].RemoveService(c, id)
|
||||
|
||||
// create service
|
||||
constraints = []string{"node.role!=worker"}
|
||||
id = daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
|
||||
tasks = daemons[0].GetServiceTasks(c, id)
|
||||
// validate tasks are running on manager nodes
|
||||
for _, task := range tasks {
|
||||
node := daemons[0].GetNode(c, task.NodeID)
|
||||
c.Assert(node.Spec.Role, checker.Equals, swarm.NodeRoleManager)
|
||||
}
|
||||
//remove service
|
||||
daemons[0].RemoveService(c, id)
|
||||
|
||||
// create service
|
||||
constraints = []string{"node.role==nosuchrole"}
|
||||
id = daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
|
||||
// wait for tasks created
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceTasks(id), checker.Equals, instances)
|
||||
// let scheduler try
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
// validate tasks are not assigned to any node
|
||||
tasks = daemons[0].GetServiceTasks(c, id)
|
||||
for _, task := range tasks {
|
||||
c.Assert(task.NodeID, checker.Equals, "")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintLabel(c *check.C) {
|
||||
const nodeCount = 3
|
||||
var daemons [nodeCount]*daemon.Daemon
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
daemons[i] = s.AddDaemon(c, true, i == 0)
|
||||
}
|
||||
// wait for nodes ready
|
||||
waitAndAssert(c, 5*time.Second, daemons[0].CheckNodeReadyCount, checker.Equals, nodeCount)
|
||||
nodes := daemons[0].ListNodes(c)
|
||||
c.Assert(len(nodes), checker.Equals, nodeCount)
|
||||
|
||||
// add labels to nodes
|
||||
daemons[0].UpdateNode(c, nodes[0].ID, func(n *swarm.Node) {
|
||||
n.Spec.Annotations.Labels = map[string]string{
|
||||
"security": "high",
|
||||
}
|
||||
})
|
||||
for i := 1; i < nodeCount; i++ {
|
||||
daemons[0].UpdateNode(c, nodes[i].ID, func(n *swarm.Node) {
|
||||
n.Spec.Annotations.Labels = map[string]string{
|
||||
"security": "low",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// create service
|
||||
instances := 3
|
||||
constraints := []string{"node.labels.security==high"}
|
||||
id := daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
|
||||
tasks := daemons[0].GetServiceTasks(c, id)
|
||||
// validate all tasks are running on nodes[0]
|
||||
for _, task := range tasks {
|
||||
c.Assert(task.NodeID, checker.Equals, nodes[0].ID)
|
||||
}
|
||||
//remove service
|
||||
daemons[0].RemoveService(c, id)
|
||||
|
||||
// create service
|
||||
constraints = []string{"node.labels.security!=high"}
|
||||
id = daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
|
||||
tasks = daemons[0].GetServiceTasks(c, id)
|
||||
// validate all tasks are NOT running on nodes[0]
|
||||
for _, task := range tasks {
|
||||
c.Assert(task.NodeID, checker.Not(checker.Equals), nodes[0].ID)
|
||||
}
|
||||
//remove service
|
||||
daemons[0].RemoveService(c, id)
|
||||
|
||||
constraints = []string{"node.labels.security==medium"}
|
||||
id = daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
|
||||
// wait for tasks created
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceTasks(id), checker.Equals, instances)
|
||||
// let scheduler try
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
tasks = daemons[0].GetServiceTasks(c, id)
|
||||
// validate tasks are not assigned
|
||||
for _, task := range tasks {
|
||||
c.Assert(task.NodeID, checker.Equals, "")
|
||||
}
|
||||
//remove service
|
||||
daemons[0].RemoveService(c, id)
|
||||
|
||||
// multiple constraints
|
||||
constraints = []string{
|
||||
"node.labels.security==high",
|
||||
fmt.Sprintf("node.id==%s", nodes[1].ID),
|
||||
}
|
||||
id = daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
|
||||
// wait for tasks created
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceTasks(id), checker.Equals, instances)
|
||||
// let scheduler try
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
tasks = daemons[0].GetServiceTasks(c, id)
|
||||
// validate tasks are not assigned
|
||||
for _, task := range tasks {
|
||||
c.Assert(task.NodeID, checker.Equals, "")
|
||||
}
|
||||
// make nodes[1] fulfills the constraints
|
||||
daemons[0].UpdateNode(c, nodes[1].ID, func(n *swarm.Node) {
|
||||
n.Spec.Annotations.Labels = map[string]string{
|
||||
"security": "high",
|
||||
}
|
||||
})
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
|
||||
tasks = daemons[0].GetServiceTasks(c, id)
|
||||
for _, task := range tasks {
|
||||
c.Assert(task.NodeID, checker.Equals, nodes[1].ID)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicePlacementPrefs(c *check.C) {
|
||||
const nodeCount = 3
|
||||
var daemons [nodeCount]*daemon.Daemon
|
||||
for i := 0; i < nodeCount; i++ {
|
||||
daemons[i] = s.AddDaemon(c, true, i == 0)
|
||||
}
|
||||
// wait for nodes ready
|
||||
waitAndAssert(c, 5*time.Second, daemons[0].CheckNodeReadyCount, checker.Equals, nodeCount)
|
||||
nodes := daemons[0].ListNodes(c)
|
||||
c.Assert(len(nodes), checker.Equals, nodeCount)
|
||||
|
||||
// add labels to nodes
|
||||
daemons[0].UpdateNode(c, nodes[0].ID, func(n *swarm.Node) {
|
||||
n.Spec.Annotations.Labels = map[string]string{
|
||||
"rack": "a",
|
||||
}
|
||||
})
|
||||
for i := 1; i < nodeCount; i++ {
|
||||
daemons[0].UpdateNode(c, nodes[i].ID, func(n *swarm.Node) {
|
||||
n.Spec.Annotations.Labels = map[string]string{
|
||||
"rack": "b",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// create service
|
||||
instances := 4
|
||||
prefs := []swarm.PlacementPreference{{Spread: &swarm.SpreadOver{SpreadDescriptor: "node.labels.rack"}}}
|
||||
id := daemons[0].CreateService(c, simpleTestService, setPlacementPrefs(prefs), setInstances(instances))
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
|
||||
tasks := daemons[0].GetServiceTasks(c, id)
|
||||
// validate all tasks are running on nodes[0]
|
||||
tasksOnNode := make(map[string]int)
|
||||
for _, task := range tasks {
|
||||
tasksOnNode[task.NodeID]++
|
||||
}
|
||||
c.Assert(tasksOnNode[nodes[0].ID], checker.Equals, 2)
|
||||
c.Assert(tasksOnNode[nodes[1].ID], checker.Equals, 1)
|
||||
c.Assert(tasksOnNode[nodes[2].ID], checker.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicesStateReporting(c *check.C) {
|
||||
testRequires(c, SameHostDaemon)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
d1 := s.AddDaemon(c, true, true)
|
||||
d2 := s.AddDaemon(c, true, true)
|
||||
d3 := s.AddDaemon(c, true, false)
|
||||
|
||||
time.Sleep(1 * time.Second) // make sure all daemons are ready to accept
|
||||
|
||||
instances := 9
|
||||
d1.CreateService(c, simpleTestService, setInstances(instances))
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
|
||||
|
||||
getContainers := func() map[string]*daemon.Daemon {
|
||||
m := make(map[string]*daemon.Daemon)
|
||||
for _, d := range []*daemon.Daemon{d1, d2, d3} {
|
||||
for _, id := range d.ActiveContainers(c) {
|
||||
m[id] = d
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
containers := getContainers()
|
||||
c.Assert(containers, checker.HasLen, instances)
|
||||
var toRemove string
|
||||
for i := range containers {
|
||||
toRemove = i
|
||||
}
|
||||
|
||||
_, err := containers[toRemove].Cmd("stop", toRemove)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
|
||||
|
||||
containers2 := getContainers()
|
||||
c.Assert(containers2, checker.HasLen, instances)
|
||||
for i := range containers {
|
||||
if i == toRemove {
|
||||
c.Assert(containers2[i], checker.IsNil)
|
||||
} else {
|
||||
c.Assert(containers2[i], checker.NotNil)
|
||||
}
|
||||
}
|
||||
|
||||
containers = containers2
|
||||
for i := range containers {
|
||||
toRemove = i
|
||||
}
|
||||
|
||||
// try with killing process outside of docker
|
||||
pidStr, err := containers[toRemove].Cmd("inspect", "-f", "{{.State.Pid}}", toRemove)
|
||||
c.Assert(err, checker.IsNil)
|
||||
pid, err := strconv.Atoi(strings.TrimSpace(pidStr))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(unix.Kill(pid, unix.SIGKILL), checker.IsNil)
|
||||
|
||||
time.Sleep(time.Second) // give some time to handle the signal
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
|
||||
|
||||
containers2 = getContainers()
|
||||
c.Assert(containers2, checker.HasLen, instances)
|
||||
for i := range containers {
|
||||
if i == toRemove {
|
||||
c.Assert(containers2[i], checker.IsNil)
|
||||
} else {
|
||||
c.Assert(containers2[i], checker.NotNil)
|
||||
}
|
||||
}
|
||||
}
|
1034
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_swarm_test.go
generated
vendored
Normal file
1034
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_swarm_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
110
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_test.go
generated
vendored
Normal file
110
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_api_test.go
generated
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestAPIOptionsRoute(c *check.C) {
|
||||
resp, _, err := request.Do("/", request.Method(http.MethodOptions))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIGetEnabledCORS(c *check.C) {
|
||||
res, body, err := request.Get("/version")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
|
||||
body.Close()
|
||||
// TODO: @runcom incomplete tests, why old integration tests had this headers
|
||||
// and here none of the headers below are in the response?
|
||||
//c.Log(res.Header)
|
||||
//c.Assert(res.Header.Get("Access-Control-Allow-Origin"), check.Equals, "*")
|
||||
//c.Assert(res.Header.Get("Access-Control-Allow-Headers"), check.Equals, "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIClientVersionOldNotSupported(c *check.C) {
|
||||
if testEnv.OSType != runtime.GOOS {
|
||||
c.Skip("Daemon platform doesn't match test platform")
|
||||
}
|
||||
if api.MinVersion == api.DefaultVersion {
|
||||
c.Skip("API MinVersion==DefaultVersion")
|
||||
}
|
||||
v := strings.Split(api.MinVersion, ".")
|
||||
vMinInt, err := strconv.Atoi(v[1])
|
||||
c.Assert(err, checker.IsNil)
|
||||
vMinInt--
|
||||
v[1] = strconv.Itoa(vMinInt)
|
||||
version := strings.Join(v, ".")
|
||||
|
||||
resp, body, err := request.Get("/v" + version + "/version")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer body.Close()
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusBadRequest)
|
||||
expected := fmt.Sprintf("client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", version, api.MinVersion)
|
||||
content, err := ioutil.ReadAll(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(string(content)), checker.Contains, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIErrorJSON(c *check.C) {
|
||||
httpResp, body, err := request.Post("/containers/create", request.JSONBody(struct{}{}))
|
||||
c.Assert(err, checker.IsNil)
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(httpResp.StatusCode, checker.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(httpResp.StatusCode, checker.Equals, http.StatusBadRequest)
|
||||
}
|
||||
c.Assert(httpResp.Header.Get("Content-Type"), checker.Equals, "application/json")
|
||||
b, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(getErrorMessage(c, b), checker.Equals, "Config cannot be empty in order to create a container")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIErrorPlainText(c *check.C) {
|
||||
// Windows requires API 1.25 or later. This test is validating a behaviour which was present
|
||||
// in v1.23, but changed in 1.24, hence not applicable on Windows. See apiVersionSupportsJSONErrors
|
||||
testRequires(c, DaemonIsLinux)
|
||||
httpResp, body, err := request.Post("/v1.23/containers/create", request.JSONBody(struct{}{}))
|
||||
c.Assert(err, checker.IsNil)
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(httpResp.StatusCode, checker.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(httpResp.StatusCode, checker.Equals, http.StatusBadRequest)
|
||||
}
|
||||
c.Assert(httpResp.Header.Get("Content-Type"), checker.Contains, "text/plain")
|
||||
b, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(string(b)), checker.Equals, "Config cannot be empty in order to create a container")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIErrorNotFoundJSON(c *check.C) {
|
||||
// 404 is a different code path to normal errors, so test separately
|
||||
httpResp, body, err := request.Get("/notfound", request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(httpResp.StatusCode, checker.Equals, http.StatusNotFound)
|
||||
c.Assert(httpResp.Header.Get("Content-Type"), checker.Equals, "application/json")
|
||||
b, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(getErrorMessage(c, b), checker.Equals, "page not found")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAPIErrorNotFoundPlainText(c *check.C) {
|
||||
httpResp, body, err := request.Get("/v1.23/notfound", request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(httpResp.StatusCode, checker.Equals, http.StatusNotFound)
|
||||
c.Assert(httpResp.Header.Get("Content-Type"), checker.Contains, "text/plain")
|
||||
b, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(string(b)), checker.Equals, "page not found")
|
||||
}
|
179
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_attach_test.go
generated
vendored
Normal file
179
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_attach_test.go
generated
vendored
Normal file
|
@ -0,0 +1,179 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
const attachWait = 5 * time.Second
|
||||
|
||||
func (s *DockerSuite) TestAttachMultipleAndRestart(c *check.C) {
|
||||
endGroup := &sync.WaitGroup{}
|
||||
startGroup := &sync.WaitGroup{}
|
||||
endGroup.Add(3)
|
||||
startGroup.Add(3)
|
||||
|
||||
cli.DockerCmd(c, "run", "--name", "attacher", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 1; echo hello; done")
|
||||
cli.WaitRun(c, "attacher")
|
||||
|
||||
startDone := make(chan struct{})
|
||||
endDone := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
endGroup.Wait()
|
||||
close(endDone)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
startGroup.Wait()
|
||||
close(startDone)
|
||||
}()
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
go func() {
|
||||
cmd := exec.Command(dockerBinary, "attach", "attacher")
|
||||
|
||||
defer func() {
|
||||
cmd.Wait()
|
||||
endGroup.Done()
|
||||
}()
|
||||
|
||||
out, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
|
||||
if _, err := out.Read(buf); err != nil && err != io.EOF {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
startGroup.Done()
|
||||
|
||||
if !strings.Contains(string(buf), "hello") {
|
||||
c.Fatalf("unexpected output %s expected hello\n", string(buf))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
select {
|
||||
case <-startDone:
|
||||
case <-time.After(attachWait):
|
||||
c.Fatalf("Attaches did not initialize properly")
|
||||
}
|
||||
|
||||
cli.DockerCmd(c, "kill", "attacher")
|
||||
|
||||
select {
|
||||
case <-endDone:
|
||||
case <-time.After(attachWait):
|
||||
c.Fatalf("Attaches did not finish properly")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAttachTTYWithoutStdin(c *check.C) {
|
||||
// TODO @jhowardmsft. Figure out how to get this running again reliable on Windows.
|
||||
// It works by accident at the moment. Sometimes. I've gone back to v1.13.0 and see the same.
|
||||
// On Windows, docker run -d -ti busybox causes the container to exit immediately.
|
||||
// Obviously a year back when I updated the test, that was not the case. However,
|
||||
// with this, and the test racing with the tear-down which panic's, sometimes CI
|
||||
// will just fail and `MISS` all the other tests. For now, disabling it. Will
|
||||
// open an issue to track re-enabling this and root-causing the problem.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "-ti", "busybox")
|
||||
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), check.IsNil)
|
||||
|
||||
done := make(chan error)
|
||||
go func() {
|
||||
defer close(done)
|
||||
|
||||
cmd := exec.Command(dockerBinary, "attach", id)
|
||||
if _, err := cmd.StdinPipe(); err != nil {
|
||||
done <- err
|
||||
return
|
||||
}
|
||||
|
||||
expected := "the input device is not a TTY"
|
||||
if runtime.GOOS == "windows" {
|
||||
expected += ". If you are using mintty, try prefixing the command with 'winpty'"
|
||||
}
|
||||
if out, _, err := runCommandWithOutput(cmd); err == nil {
|
||||
done <- fmt.Errorf("attach should have failed")
|
||||
return
|
||||
} else if !strings.Contains(out, expected) {
|
||||
done <- fmt.Errorf("attach failed with error %q: expected %q", out, expected)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-done:
|
||||
c.Assert(err, check.IsNil)
|
||||
case <-time.After(attachWait):
|
||||
c.Fatal("attach is running but should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAttachDisconnect(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-di", "busybox", "/bin/cat")
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
cmd := exec.Command(dockerBinary, "attach", id)
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
defer stdin.Close()
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
c.Assert(err, check.IsNil)
|
||||
defer stdout.Close()
|
||||
c.Assert(cmd.Start(), check.IsNil)
|
||||
defer func() {
|
||||
cmd.Process.Kill()
|
||||
cmd.Wait()
|
||||
}()
|
||||
|
||||
_, err = stdin.Write([]byte("hello\n"))
|
||||
c.Assert(err, check.IsNil)
|
||||
out, err = bufio.NewReader(stdout).ReadString('\n')
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, "hello")
|
||||
|
||||
c.Assert(stdin.Close(), check.IsNil)
|
||||
|
||||
// Expect container to still be running after stdin is closed
|
||||
running := inspectField(c, id, "State.Running")
|
||||
c.Assert(running, check.Equals, "true")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAttachPausedContainer(c *check.C) {
|
||||
testRequires(c, IsPausable)
|
||||
runSleepingContainer(c, "-d", "--name=test")
|
||||
dockerCmd(c, "pause", "test")
|
||||
|
||||
result := dockerCmdWithResult("attach", "test")
|
||||
result.Assert(c, icmd.Expected{
|
||||
Error: "exit status 1",
|
||||
ExitCode: 1,
|
||||
Err: "You cannot attach to a paused container, unpause it first",
|
||||
})
|
||||
}
|
229
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_attach_unix_test.go
generated
vendored
Normal file
229
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_attach_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,229 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/go-check/check"
|
||||
"github.com/kr/pty"
|
||||
)
|
||||
|
||||
// #9860 Make sure attach ends when container ends (with no errors)
|
||||
func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) {
|
||||
testRequires(c, SameHostDaemon)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-dti", "busybox", "/bin/sh", "-c", `trap 'exit 0' SIGTERM; while true; do sleep 1; done`)
|
||||
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), check.IsNil)
|
||||
|
||||
pty, tty, err := pty.Open()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
attachCmd := exec.Command(dockerBinary, "attach", id)
|
||||
attachCmd.Stdin = tty
|
||||
attachCmd.Stdout = tty
|
||||
attachCmd.Stderr = tty
|
||||
err = attachCmd.Start()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
defer close(errChan)
|
||||
// Container is waiting for us to signal it to stop
|
||||
dockerCmd(c, "stop", id)
|
||||
// And wait for the attach command to end
|
||||
errChan <- attachCmd.Wait()
|
||||
}()
|
||||
|
||||
// Wait for the docker to end (should be done by the
|
||||
// stop command in the go routine)
|
||||
dockerCmd(c, "wait", id)
|
||||
|
||||
select {
|
||||
case err := <-errChan:
|
||||
tty.Close()
|
||||
out, _ := ioutil.ReadAll(pty)
|
||||
c.Assert(err, check.IsNil, check.Commentf("out: %v", string(out)))
|
||||
case <-time.After(attachWait):
|
||||
c.Fatal("timed out without attach returning")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestAttachAfterDetach(c *check.C) {
|
||||
name := "detachtest"
|
||||
|
||||
cpty, tty, err := pty.Open()
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Could not open pty: %v", err))
|
||||
cmd := exec.Command(dockerBinary, "run", "-ti", "--name", name, "busybox")
|
||||
cmd.Stdin = tty
|
||||
cmd.Stdout = tty
|
||||
cmd.Stderr = tty
|
||||
|
||||
cmdExit := make(chan error)
|
||||
go func() {
|
||||
cmdExit <- cmd.Run()
|
||||
close(cmdExit)
|
||||
}()
|
||||
|
||||
c.Assert(waitRun(name), check.IsNil)
|
||||
|
||||
cpty.Write([]byte{16})
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
cpty.Write([]byte{17})
|
||||
|
||||
select {
|
||||
case <-cmdExit:
|
||||
case <-time.After(5 * time.Second):
|
||||
c.Fatal("timeout while detaching")
|
||||
}
|
||||
|
||||
cpty, tty, err = pty.Open()
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Could not open pty: %v", err))
|
||||
|
||||
cmd = exec.Command(dockerBinary, "attach", name)
|
||||
cmd.Stdin = tty
|
||||
cmd.Stdout = tty
|
||||
cmd.Stderr = tty
|
||||
|
||||
err = cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
bytes := make([]byte, 10)
|
||||
var nBytes int
|
||||
readErr := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
cpty.Write([]byte("\n"))
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
nBytes, err = cpty.Read(bytes)
|
||||
cpty.Close()
|
||||
readErr <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-readErr:
|
||||
c.Assert(err, check.IsNil)
|
||||
case <-time.After(2 * time.Second):
|
||||
c.Fatal("timeout waiting for attach read")
|
||||
}
|
||||
|
||||
c.Assert(string(bytes[:nBytes]), checker.Contains, "/ #")
|
||||
}
|
||||
|
||||
// TestAttachDetach checks that attach in tty mode can be detached using the long container ID
|
||||
func (s *DockerSuite) TestAttachDetach(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat")
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), check.IsNil)
|
||||
|
||||
cpty, tty, err := pty.Open()
|
||||
c.Assert(err, check.IsNil)
|
||||
defer cpty.Close()
|
||||
|
||||
cmd := exec.Command(dockerBinary, "attach", id)
|
||||
cmd.Stdin = tty
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
c.Assert(err, check.IsNil)
|
||||
defer stdout.Close()
|
||||
err = cmd.Start()
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(waitRun(id), check.IsNil)
|
||||
|
||||
_, err = cpty.Write([]byte("hello\n"))
|
||||
c.Assert(err, check.IsNil)
|
||||
out, err = bufio.NewReader(stdout).ReadString('\n')
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "hello", check.Commentf("expected 'hello', got %q", out))
|
||||
|
||||
// escape sequence
|
||||
_, err = cpty.Write([]byte{16})
|
||||
c.Assert(err, checker.IsNil)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
_, err = cpty.Write([]byte{17})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
cmd.Wait()
|
||||
ch <- struct{}{}
|
||||
}()
|
||||
|
||||
running := inspectField(c, id, "State.Running")
|
||||
c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running"))
|
||||
|
||||
go func() {
|
||||
dockerCmdWithResult("kill", id)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
c.Fatal("timed out waiting for container to exit")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TestAttachDetachTruncatedID checks that attach in tty mode can be detached
|
||||
func (s *DockerSuite) TestAttachDetachTruncatedID(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat")
|
||||
id := stringid.TruncateID(strings.TrimSpace(out))
|
||||
c.Assert(waitRun(id), check.IsNil)
|
||||
|
||||
cpty, tty, err := pty.Open()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cpty.Close()
|
||||
|
||||
cmd := exec.Command(dockerBinary, "attach", id)
|
||||
cmd.Stdin = tty
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer stdout.Close()
|
||||
err = cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = cpty.Write([]byte("hello\n"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
out, err = bufio.NewReader(stdout).ReadString('\n')
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "hello", check.Commentf("expected 'hello', got %q", out))
|
||||
|
||||
// escape sequence
|
||||
_, err = cpty.Write([]byte{16})
|
||||
c.Assert(err, checker.IsNil)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
_, err = cpty.Write([]byte{17})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
cmd.Wait()
|
||||
ch <- struct{}{}
|
||||
}()
|
||||
|
||||
running := inspectField(c, id, "State.Running")
|
||||
c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running"))
|
||||
|
||||
go func() {
|
||||
dockerCmdWithResult("kill", id)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
c.Fatal("timed out waiting for container to exit")
|
||||
}
|
||||
|
||||
}
|
6205
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_build_test.go
generated
vendored
Normal file
6205
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_build_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
228
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_build_unix_test.go
generated
vendored
Normal file
228
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_build_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,228 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/internal/test/fakecontext"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestBuildResourceConstraintsAreUsed(c *check.C) {
|
||||
testRequires(c, cpuCfsQuota)
|
||||
name := "testbuildresourceconstraints"
|
||||
buildLabel := "DockerSuite.TestBuildResourceConstraintsAreUsed"
|
||||
|
||||
ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`
|
||||
FROM hello-world:frozen
|
||||
RUN ["/hello"]
|
||||
`))
|
||||
cli.Docker(
|
||||
cli.Args("build", "--no-cache", "--rm=false", "--memory=64m", "--memory-swap=-1", "--cpuset-cpus=0", "--cpuset-mems=0", "--cpu-shares=100", "--cpu-quota=8000", "--ulimit", "nofile=42", "--label="+buildLabel, "-t", name, "."),
|
||||
cli.InDir(ctx.Dir),
|
||||
).Assert(c, icmd.Success)
|
||||
|
||||
out := cli.DockerCmd(c, "ps", "-lq", "--filter", "label="+buildLabel).Combined()
|
||||
cID := strings.TrimSpace(out)
|
||||
|
||||
type hostConfig struct {
|
||||
Memory int64
|
||||
MemorySwap int64
|
||||
CpusetCpus string
|
||||
CpusetMems string
|
||||
CPUShares int64
|
||||
CPUQuota int64
|
||||
Ulimits []*units.Ulimit
|
||||
}
|
||||
|
||||
cfg := inspectFieldJSON(c, cID, "HostConfig")
|
||||
|
||||
var c1 hostConfig
|
||||
err := json.Unmarshal([]byte(cfg), &c1)
|
||||
c.Assert(err, checker.IsNil, check.Commentf(cfg))
|
||||
|
||||
c.Assert(c1.Memory, checker.Equals, int64(64*1024*1024), check.Commentf("resource constraints not set properly for Memory"))
|
||||
c.Assert(c1.MemorySwap, checker.Equals, int64(-1), check.Commentf("resource constraints not set properly for MemorySwap"))
|
||||
c.Assert(c1.CpusetCpus, checker.Equals, "0", check.Commentf("resource constraints not set properly for CpusetCpus"))
|
||||
c.Assert(c1.CpusetMems, checker.Equals, "0", check.Commentf("resource constraints not set properly for CpusetMems"))
|
||||
c.Assert(c1.CPUShares, checker.Equals, int64(100), check.Commentf("resource constraints not set properly for CPUShares"))
|
||||
c.Assert(c1.CPUQuota, checker.Equals, int64(8000), check.Commentf("resource constraints not set properly for CPUQuota"))
|
||||
c.Assert(c1.Ulimits[0].Name, checker.Equals, "nofile", check.Commentf("resource constraints not set properly for Ulimits"))
|
||||
c.Assert(c1.Ulimits[0].Hard, checker.Equals, int64(42), check.Commentf("resource constraints not set properly for Ulimits"))
|
||||
|
||||
// Make sure constraints aren't saved to image
|
||||
cli.DockerCmd(c, "run", "--name=test", name)
|
||||
|
||||
cfg = inspectFieldJSON(c, "test", "HostConfig")
|
||||
|
||||
var c2 hostConfig
|
||||
err = json.Unmarshal([]byte(cfg), &c2)
|
||||
c.Assert(err, checker.IsNil, check.Commentf(cfg))
|
||||
|
||||
c.Assert(c2.Memory, check.Not(checker.Equals), int64(64*1024*1024), check.Commentf("resource leaked from build for Memory"))
|
||||
c.Assert(c2.MemorySwap, check.Not(checker.Equals), int64(-1), check.Commentf("resource leaked from build for MemorySwap"))
|
||||
c.Assert(c2.CpusetCpus, check.Not(checker.Equals), "0", check.Commentf("resource leaked from build for CpusetCpus"))
|
||||
c.Assert(c2.CpusetMems, check.Not(checker.Equals), "0", check.Commentf("resource leaked from build for CpusetMems"))
|
||||
c.Assert(c2.CPUShares, check.Not(checker.Equals), int64(100), check.Commentf("resource leaked from build for CPUShares"))
|
||||
c.Assert(c2.CPUQuota, check.Not(checker.Equals), int64(8000), check.Commentf("resource leaked from build for CPUQuota"))
|
||||
c.Assert(c2.Ulimits, checker.IsNil, check.Commentf("resource leaked from build for Ulimits"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildAddChangeOwnership(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "testbuildaddown"
|
||||
|
||||
ctx := func() *fakecontext.Fake {
|
||||
dockerfile := `
|
||||
FROM busybox
|
||||
ADD foo /bar/
|
||||
RUN [ $(stat -c %U:%G "/bar") = 'root:root' ]
|
||||
RUN [ $(stat -c %U:%G "/bar/foo") = 'root:root' ]
|
||||
`
|
||||
tmpDir, err := ioutil.TempDir("", "fake-context")
|
||||
c.Assert(err, check.IsNil)
|
||||
testFile, err := os.Create(filepath.Join(tmpDir, "foo"))
|
||||
if err != nil {
|
||||
c.Fatalf("failed to create foo file: %v", err)
|
||||
}
|
||||
defer testFile.Close()
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{"chown", "daemon:daemon", "foo"},
|
||||
Dir: tmpDir,
|
||||
}).Assert(c, icmd.Success)
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
|
||||
c.Fatalf("failed to open destination dockerfile: %v", err)
|
||||
}
|
||||
return fakecontext.New(c, tmpDir)
|
||||
}()
|
||||
|
||||
defer ctx.Close()
|
||||
|
||||
buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
|
||||
}
|
||||
|
||||
// Test that an infinite sleep during a build is killed if the client disconnects.
|
||||
// This test is fairly hairy because there are lots of ways to race.
|
||||
// Strategy:
|
||||
// * Monitor the output of docker events starting from before
|
||||
// * Run a 1-year-long sleep from a docker build.
|
||||
// * When docker events sees container start, close the "docker build" command
|
||||
// * Wait for docker events to emit a dying event.
|
||||
//
|
||||
// TODO(buildkit): this test needs to be rewritten for buildkit.
|
||||
// It has been manually tested positive. Confirmed issue: docker build output parsing.
|
||||
// Potential issue: newEventObserver uses docker events, which is not hooked up to buildkit.
|
||||
func (s *DockerSuite) TestBuildCancellationKillsSleep(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, TODOBuildkit)
|
||||
name := "testbuildcancellation"
|
||||
|
||||
observer, err := newEventObserver(c)
|
||||
c.Assert(err, checker.IsNil)
|
||||
err = observer.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer observer.Stop()
|
||||
|
||||
// (Note: one year, will never finish)
|
||||
ctx := fakecontext.New(c, "", fakecontext.WithDockerfile("FROM busybox\nRUN sleep 31536000"))
|
||||
defer ctx.Close()
|
||||
|
||||
buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".")
|
||||
buildCmd.Dir = ctx.Dir
|
||||
|
||||
stdoutBuild, err := buildCmd.StdoutPipe()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
if err := buildCmd.Start(); err != nil {
|
||||
c.Fatalf("failed to run build: %s", err)
|
||||
}
|
||||
// always clean up
|
||||
defer func() {
|
||||
buildCmd.Process.Kill()
|
||||
buildCmd.Wait()
|
||||
}()
|
||||
|
||||
matchCID := regexp.MustCompile("Running in (.+)")
|
||||
scanner := bufio.NewScanner(stdoutBuild)
|
||||
|
||||
outputBuffer := new(bytes.Buffer)
|
||||
var buildID string
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
outputBuffer.WriteString(line)
|
||||
outputBuffer.WriteString("\n")
|
||||
if matches := matchCID.FindStringSubmatch(line); len(matches) > 0 {
|
||||
buildID = matches[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if buildID == "" {
|
||||
c.Fatalf("Unable to find build container id in build output:\n%s", outputBuffer.String())
|
||||
}
|
||||
|
||||
testActions := map[string]chan bool{
|
||||
"start": make(chan bool, 1),
|
||||
"die": make(chan bool, 1),
|
||||
}
|
||||
|
||||
matcher := matchEventLine(buildID, "container", testActions)
|
||||
processor := processEventMatch(testActions)
|
||||
go observer.Match(matcher, processor)
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
observer.CheckEventError(c, buildID, "start", matcher)
|
||||
case <-testActions["start"]:
|
||||
// ignore, done
|
||||
}
|
||||
|
||||
// Send a kill to the `docker build` command.
|
||||
// Causes the underlying build to be cancelled due to socket close.
|
||||
if err := buildCmd.Process.Kill(); err != nil {
|
||||
c.Fatalf("error killing build command: %s", err)
|
||||
}
|
||||
|
||||
// Get the exit status of `docker build`, check it exited because killed.
|
||||
if err := buildCmd.Wait(); err != nil && !isKilled(err) {
|
||||
c.Fatalf("wait failed during build run: %T %s", err, err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
observer.CheckEventError(c, buildID, "die", matcher)
|
||||
case <-testActions["die"]:
|
||||
// ignore, done
|
||||
}
|
||||
}
|
||||
|
||||
func isKilled(err error) bool {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
status, ok := exitErr.Sys().(syscall.WaitStatus)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
// status.ExitStatus() is required on Windows because it does not
|
||||
// implement Signal() nor Signaled(). Just check it had a bad exit
|
||||
// status could mean it was killed (and in tests we do kill)
|
||||
return (status.Signaled() && status.Signal() == os.Kill) || status.ExitStatus() != 0
|
||||
}
|
||||
return false
|
||||
}
|
693
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_by_digest_test.go
generated
vendored
Normal file
693
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_by_digest_test.go
generated
vendored
Normal file
|
@ -0,0 +1,693 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
var (
|
||||
remoteRepoName = "dockercli/busybox-by-dgst"
|
||||
repoName = fmt.Sprintf("%s/%s", privateRegistryURL, remoteRepoName)
|
||||
pushDigestRegex = regexp.MustCompile("[\\S]+: digest: ([\\S]+) size: [0-9]+")
|
||||
digestRegex = regexp.MustCompile("Digest: ([\\S]+)")
|
||||
)
|
||||
|
||||
func setupImage(c *check.C) (digest.Digest, error) {
|
||||
return setupImageWithTag(c, "latest")
|
||||
}
|
||||
|
||||
func setupImageWithTag(c *check.C, tag string) (digest.Digest, error) {
|
||||
containerName := "busyboxbydigest"
|
||||
|
||||
// new file is committed because this layer is used for detecting malicious
|
||||
// changes. if this was committed as empty layer it would be skipped on pull
|
||||
// and malicious changes would never be detected.
|
||||
cli.DockerCmd(c, "run", "-e", "digest=1", "--name", containerName, "busybox", "touch", "anewfile")
|
||||
|
||||
// tag the image to upload it to the private registry
|
||||
repoAndTag := repoName + ":" + tag
|
||||
cli.DockerCmd(c, "commit", containerName, repoAndTag)
|
||||
|
||||
// delete the container as we don't need it any more
|
||||
cli.DockerCmd(c, "rm", "-fv", containerName)
|
||||
|
||||
// push the image
|
||||
out := cli.DockerCmd(c, "push", repoAndTag).Combined()
|
||||
|
||||
// delete our local repo that we previously tagged
|
||||
cli.DockerCmd(c, "rmi", repoAndTag)
|
||||
|
||||
matches := pushDigestRegex.FindStringSubmatch(out)
|
||||
c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from push output: %s", out))
|
||||
pushDigest := matches[1]
|
||||
|
||||
return digest.Digest(pushDigest), nil
|
||||
}
|
||||
|
||||
func testPullByTagDisplaysDigest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
pushDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
// pull from the registry using the tag
|
||||
out, _ := dockerCmd(c, "pull", repoName)
|
||||
|
||||
// the pull output includes "Digest: <digest>", so find that
|
||||
matches := digestRegex.FindStringSubmatch(out)
|
||||
c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from pull output: %s", out))
|
||||
pullDigest := matches[1]
|
||||
|
||||
// make sure the pushed and pull digests match
|
||||
c.Assert(pushDigest.String(), checker.Equals, pullDigest)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPullByTagDisplaysDigest(c *check.C) {
|
||||
testPullByTagDisplaysDigest(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPullByTagDisplaysDigest(c *check.C) {
|
||||
testPullByTagDisplaysDigest(c)
|
||||
}
|
||||
|
||||
func testPullByDigest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
pushDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
|
||||
out, _ := dockerCmd(c, "pull", imageReference)
|
||||
|
||||
// the pull output includes "Digest: <digest>", so find that
|
||||
matches := digestRegex.FindStringSubmatch(out)
|
||||
c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from pull output: %s", out))
|
||||
pullDigest := matches[1]
|
||||
|
||||
// make sure the pushed and pull digests match
|
||||
c.Assert(pushDigest.String(), checker.Equals, pullDigest)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPullByDigest(c *check.C) {
|
||||
testPullByDigest(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPullByDigest(c *check.C) {
|
||||
testPullByDigest(c)
|
||||
}
|
||||
|
||||
func testPullByDigestNoFallback(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
imageReference := fmt.Sprintf("%s@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", repoName)
|
||||
out, _, err := dockerCmdWithError("pull", imageReference)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("expected non-zero exit status and correct error message when pulling non-existing image"))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("manifest for %s not found", imageReference), check.Commentf("expected non-zero exit status and correct error message when pulling non-existing image"))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPullByDigestNoFallback(c *check.C) {
|
||||
testPullByDigestNoFallback(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPullByDigestNoFallback(c *check.C) {
|
||||
testPullByDigestNoFallback(c)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestCreateByDigest(c *check.C) {
|
||||
pushDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
|
||||
|
||||
containerName := "createByDigest"
|
||||
dockerCmd(c, "create", "--name", containerName, imageReference)
|
||||
|
||||
res := inspectField(c, containerName, "Config.Image")
|
||||
c.Assert(res, checker.Equals, imageReference)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestRunByDigest(c *check.C) {
|
||||
pushDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
|
||||
|
||||
containerName := "runByDigest"
|
||||
out, _ := dockerCmd(c, "run", "--name", containerName, imageReference, "sh", "-c", "echo found=$digest")
|
||||
|
||||
foundRegex := regexp.MustCompile("found=([^\n]+)")
|
||||
matches := foundRegex.FindStringSubmatch(out)
|
||||
c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from pull output: %s", out))
|
||||
c.Assert(matches[1], checker.Equals, "1", check.Commentf("Expected %q, got %q", "1", matches[1]))
|
||||
|
||||
res := inspectField(c, containerName, "Config.Image")
|
||||
c.Assert(res, checker.Equals, imageReference)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestRemoveImageByDigest(c *check.C) {
|
||||
digest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, digest)
|
||||
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
dockerCmd(c, "pull", imageReference)
|
||||
|
||||
// make sure inspect runs ok
|
||||
inspectField(c, imageReference, "Id")
|
||||
|
||||
// do the delete
|
||||
err = deleteImages(imageReference)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unexpected error deleting image"))
|
||||
|
||||
// try to inspect again - it should error this time
|
||||
_, err = inspectFieldWithError(imageReference, "Id")
|
||||
//unexpected nil err trying to inspect what should be a non-existent image
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(err.Error(), checker.Contains, "No such object")
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestBuildByDigest(c *check.C) {
|
||||
digest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, digest)
|
||||
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
dockerCmd(c, "pull", imageReference)
|
||||
|
||||
// get the image id
|
||||
imageID := inspectField(c, imageReference, "Id")
|
||||
|
||||
// do the build
|
||||
name := "buildbydigest"
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(
|
||||
`FROM %s
|
||||
CMD ["/bin/echo", "Hello World"]`, imageReference)))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// get the build's image id
|
||||
res := inspectField(c, name, "Config.Image")
|
||||
// make sure they match
|
||||
c.Assert(res, checker.Equals, imageID)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestTagByDigest(c *check.C) {
|
||||
digest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, digest)
|
||||
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
dockerCmd(c, "pull", imageReference)
|
||||
|
||||
// tag it
|
||||
tag := "tagbydigest"
|
||||
dockerCmd(c, "tag", imageReference, tag)
|
||||
|
||||
expectedID := inspectField(c, imageReference, "Id")
|
||||
|
||||
tagID := inspectField(c, tag, "Id")
|
||||
c.Assert(tagID, checker.Equals, expectedID)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestListImagesWithoutDigests(c *check.C) {
|
||||
digest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, digest)
|
||||
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
dockerCmd(c, "pull", imageReference)
|
||||
|
||||
out, _ := dockerCmd(c, "images")
|
||||
c.Assert(out, checker.Not(checker.Contains), "DIGEST", check.Commentf("list output should not have contained DIGEST header"))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestListImagesWithDigests(c *check.C) {
|
||||
|
||||
// setup image1
|
||||
digest1, err := setupImageWithTag(c, "tag1")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
imageReference1 := fmt.Sprintf("%s@%s", repoName, digest1)
|
||||
c.Logf("imageReference1 = %s", imageReference1)
|
||||
|
||||
// pull image1 by digest
|
||||
dockerCmd(c, "pull", imageReference1)
|
||||
|
||||
// list images
|
||||
out, _ := dockerCmd(c, "images", "--digests")
|
||||
|
||||
// make sure repo shown, tag=<none>, digest = $digest1
|
||||
re1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1.String() + `\s`)
|
||||
c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out))
|
||||
// setup image2
|
||||
digest2, err := setupImageWithTag(c, "tag2")
|
||||
//error setting up image
|
||||
c.Assert(err, checker.IsNil)
|
||||
imageReference2 := fmt.Sprintf("%s@%s", repoName, digest2)
|
||||
c.Logf("imageReference2 = %s", imageReference2)
|
||||
|
||||
// pull image1 by digest
|
||||
dockerCmd(c, "pull", imageReference1)
|
||||
|
||||
// pull image2 by digest
|
||||
dockerCmd(c, "pull", imageReference2)
|
||||
|
||||
// list images
|
||||
out, _ = dockerCmd(c, "images", "--digests")
|
||||
|
||||
// make sure repo shown, tag=<none>, digest = $digest1
|
||||
c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out))
|
||||
|
||||
// make sure repo shown, tag=<none>, digest = $digest2
|
||||
re2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2.String() + `\s`)
|
||||
c.Assert(re2.MatchString(out), checker.True, check.Commentf("expected %q: %s", re2.String(), out))
|
||||
|
||||
// pull tag1
|
||||
dockerCmd(c, "pull", repoName+":tag1")
|
||||
|
||||
// list images
|
||||
out, _ = dockerCmd(c, "images", "--digests")
|
||||
|
||||
// make sure image 1 has repo, tag, <none> AND repo, <none>, digest
|
||||
reWithDigest1 := regexp.MustCompile(`\s*` + repoName + `\s*tag1\s*` + digest1.String() + `\s`)
|
||||
c.Assert(reWithDigest1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest1.String(), out))
|
||||
// make sure image 2 has repo, <none>, digest
|
||||
c.Assert(re2.MatchString(out), checker.True, check.Commentf("expected %q: %s", re2.String(), out))
|
||||
|
||||
// pull tag 2
|
||||
dockerCmd(c, "pull", repoName+":tag2")
|
||||
|
||||
// list images
|
||||
out, _ = dockerCmd(c, "images", "--digests")
|
||||
|
||||
// make sure image 1 has repo, tag, digest
|
||||
c.Assert(reWithDigest1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest1.String(), out))
|
||||
|
||||
// make sure image 2 has repo, tag, digest
|
||||
reWithDigest2 := regexp.MustCompile(`\s*` + repoName + `\s*tag2\s*` + digest2.String() + `\s`)
|
||||
c.Assert(reWithDigest2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest2.String(), out))
|
||||
|
||||
// list images
|
||||
out, _ = dockerCmd(c, "images", "--digests")
|
||||
|
||||
// make sure image 1 has repo, tag, digest
|
||||
c.Assert(reWithDigest1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest1.String(), out))
|
||||
// make sure image 2 has repo, tag, digest
|
||||
c.Assert(reWithDigest2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest2.String(), out))
|
||||
// make sure busybox has tag, but not digest
|
||||
busyboxRe := regexp.MustCompile(`\s*busybox\s*latest\s*<none>\s`)
|
||||
c.Assert(busyboxRe.MatchString(out), checker.True, check.Commentf("expected %q: %s", busyboxRe.String(), out))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestListDanglingImagesWithDigests(c *check.C) {
|
||||
// setup image1
|
||||
digest1, err := setupImageWithTag(c, "dangle1")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
imageReference1 := fmt.Sprintf("%s@%s", repoName, digest1)
|
||||
c.Logf("imageReference1 = %s", imageReference1)
|
||||
|
||||
// pull image1 by digest
|
||||
dockerCmd(c, "pull", imageReference1)
|
||||
|
||||
// list images
|
||||
out, _ := dockerCmd(c, "images", "--digests")
|
||||
|
||||
// make sure repo shown, tag=<none>, digest = $digest1
|
||||
re1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1.String() + `\s`)
|
||||
c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out))
|
||||
// setup image2
|
||||
digest2, err := setupImageWithTag(c, "dangle2")
|
||||
//error setting up image
|
||||
c.Assert(err, checker.IsNil)
|
||||
imageReference2 := fmt.Sprintf("%s@%s", repoName, digest2)
|
||||
c.Logf("imageReference2 = %s", imageReference2)
|
||||
|
||||
// pull image1 by digest
|
||||
dockerCmd(c, "pull", imageReference1)
|
||||
|
||||
// pull image2 by digest
|
||||
dockerCmd(c, "pull", imageReference2)
|
||||
|
||||
// list images
|
||||
out, _ = dockerCmd(c, "images", "--digests", "--filter=dangling=true")
|
||||
|
||||
// make sure repo shown, tag=<none>, digest = $digest1
|
||||
c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out))
|
||||
|
||||
// make sure repo shown, tag=<none>, digest = $digest2
|
||||
re2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2.String() + `\s`)
|
||||
c.Assert(re2.MatchString(out), checker.True, check.Commentf("expected %q: %s", re2.String(), out))
|
||||
|
||||
// pull dangle1 tag
|
||||
dockerCmd(c, "pull", repoName+":dangle1")
|
||||
|
||||
// list images
|
||||
out, _ = dockerCmd(c, "images", "--digests", "--filter=dangling=true")
|
||||
|
||||
// make sure image 1 has repo, tag, <none> AND repo, <none>, digest
|
||||
reWithDigest1 := regexp.MustCompile(`\s*` + repoName + `\s*dangle1\s*` + digest1.String() + `\s`)
|
||||
c.Assert(reWithDigest1.MatchString(out), checker.False, check.Commentf("unexpected %q: %s", reWithDigest1.String(), out))
|
||||
// make sure image 2 has repo, <none>, digest
|
||||
c.Assert(re2.MatchString(out), checker.True, check.Commentf("expected %q: %s", re2.String(), out))
|
||||
|
||||
// pull dangle2 tag
|
||||
dockerCmd(c, "pull", repoName+":dangle2")
|
||||
|
||||
// list images, show tagged images
|
||||
out, _ = dockerCmd(c, "images", "--digests")
|
||||
|
||||
// make sure image 1 has repo, tag, digest
|
||||
c.Assert(reWithDigest1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest1.String(), out))
|
||||
|
||||
// make sure image 2 has repo, tag, digest
|
||||
reWithDigest2 := regexp.MustCompile(`\s*` + repoName + `\s*dangle2\s*` + digest2.String() + `\s`)
|
||||
c.Assert(reWithDigest2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest2.String(), out))
|
||||
|
||||
// list images, no longer dangling, should not match
|
||||
out, _ = dockerCmd(c, "images", "--digests", "--filter=dangling=true")
|
||||
|
||||
// make sure image 1 has repo, tag, digest
|
||||
c.Assert(reWithDigest1.MatchString(out), checker.False, check.Commentf("unexpected %q: %s", reWithDigest1.String(), out))
|
||||
// make sure image 2 has repo, tag, digest
|
||||
c.Assert(reWithDigest2.MatchString(out), checker.False, check.Commentf("unexpected %q: %s", reWithDigest2.String(), out))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestInspectImageWithDigests(c *check.C) {
|
||||
digest, err := setupImage(c)
|
||||
c.Assert(err, check.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, digest)
|
||||
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
dockerCmd(c, "pull", imageReference)
|
||||
|
||||
out, _ := dockerCmd(c, "inspect", imageReference)
|
||||
|
||||
var imageJSON []types.ImageInspect
|
||||
err = json.Unmarshal([]byte(out), &imageJSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(imageJSON, checker.HasLen, 1)
|
||||
c.Assert(imageJSON[0].RepoDigests, checker.HasLen, 1)
|
||||
assert.Check(c, is.Contains(imageJSON[0].RepoDigests, imageReference))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPsListContainersFilterAncestorImageByDigest(c *check.C) {
|
||||
existingContainers := ExistingContainerIDs(c)
|
||||
|
||||
digest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, digest)
|
||||
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
dockerCmd(c, "pull", imageReference)
|
||||
|
||||
// build an image from it
|
||||
imageName1 := "images_ps_filter_test"
|
||||
buildImageSuccessfully(c, imageName1, build.WithDockerfile(fmt.Sprintf(
|
||||
`FROM %s
|
||||
LABEL match me 1`, imageReference)))
|
||||
|
||||
// run a container based on that
|
||||
dockerCmd(c, "run", "--name=test1", imageReference, "echo", "hello")
|
||||
expectedID := getIDByName(c, "test1")
|
||||
|
||||
// run a container based on the a descendant of that too
|
||||
dockerCmd(c, "run", "--name=test2", imageName1, "echo", "hello")
|
||||
expectedID1 := getIDByName(c, "test2")
|
||||
|
||||
expectedIDs := []string{expectedID, expectedID1}
|
||||
|
||||
// Invalid imageReference
|
||||
out, _ := dockerCmd(c, "ps", "-a", "-q", "--no-trunc", fmt.Sprintf("--filter=ancestor=busybox@%s", digest))
|
||||
// Filter container for ancestor filter should be empty
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "")
|
||||
|
||||
// Valid imageReference
|
||||
out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=ancestor="+imageReference)
|
||||
checkPsAncestorFilterOutput(c, RemoveOutputForExistingElements(out, existingContainers), imageReference, expectedIDs)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestDeleteImageByIDOnlyPulledByDigest(c *check.C) {
|
||||
pushDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
|
||||
dockerCmd(c, "pull", imageReference)
|
||||
// just in case...
|
||||
|
||||
dockerCmd(c, "tag", imageReference, repoName+":sometag")
|
||||
|
||||
imageID := inspectField(c, imageReference, "Id")
|
||||
|
||||
dockerCmd(c, "rmi", imageID)
|
||||
|
||||
_, err = inspectFieldWithError(imageID, "Id")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("image should have been deleted"))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestDeleteImageWithDigestAndTag(c *check.C) {
|
||||
pushDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
|
||||
dockerCmd(c, "pull", imageReference)
|
||||
|
||||
imageID := inspectField(c, imageReference, "Id")
|
||||
|
||||
repoTag := repoName + ":sometag"
|
||||
repoTag2 := repoName + ":othertag"
|
||||
dockerCmd(c, "tag", imageReference, repoTag)
|
||||
dockerCmd(c, "tag", imageReference, repoTag2)
|
||||
|
||||
dockerCmd(c, "rmi", repoTag2)
|
||||
|
||||
// rmi should have deleted only repoTag2, because there's another tag
|
||||
inspectField(c, repoTag, "Id")
|
||||
|
||||
dockerCmd(c, "rmi", repoTag)
|
||||
|
||||
// rmi should have deleted the tag, the digest reference, and the image itself
|
||||
_, err = inspectFieldWithError(imageID, "Id")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("image should have been deleted"))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestDeleteImageWithDigestAndMultiRepoTag(c *check.C) {
|
||||
pushDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
repo2 := fmt.Sprintf("%s/%s", repoName, "repo2")
|
||||
|
||||
// pull from the registry using the <name>@<digest> reference
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest)
|
||||
dockerCmd(c, "pull", imageReference)
|
||||
|
||||
imageID := inspectField(c, imageReference, "Id")
|
||||
|
||||
repoTag := repoName + ":sometag"
|
||||
repoTag2 := repo2 + ":othertag"
|
||||
dockerCmd(c, "tag", imageReference, repoTag)
|
||||
dockerCmd(c, "tag", imageReference, repoTag2)
|
||||
|
||||
dockerCmd(c, "rmi", repoTag)
|
||||
|
||||
// rmi should have deleted repoTag and image reference, but left repoTag2
|
||||
inspectField(c, repoTag2, "Id")
|
||||
_, err = inspectFieldWithError(imageReference, "Id")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("image digest reference should have been removed"))
|
||||
|
||||
_, err = inspectFieldWithError(repoTag, "Id")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("image tag reference should have been removed"))
|
||||
|
||||
dockerCmd(c, "rmi", repoTag2)
|
||||
|
||||
// rmi should have deleted the tag, the digest reference, and the image itself
|
||||
_, err = inspectFieldWithError(imageID, "Id")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("image should have been deleted"))
|
||||
}
|
||||
|
||||
// TestPullFailsWithAlteredManifest tests that a `docker pull` fails when
|
||||
// we have modified a manifest blob and its digest cannot be verified.
|
||||
// This is the schema2 version of the test.
|
||||
func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
manifestDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
// Load the target manifest blob.
|
||||
manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
|
||||
|
||||
var imgManifest schema2.Manifest
|
||||
err = json.Unmarshal(manifestBlob, &imgManifest)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to decode image manifest from blob"))
|
||||
|
||||
// Change a layer in the manifest.
|
||||
imgManifest.Layers[0].Digest = digest.Digest("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
|
||||
// Move the existing data file aside, so that we can replace it with a
|
||||
// malicious blob of data. NOTE: we defer the returned undo func.
|
||||
undo := s.reg.TempMoveBlobData(c, manifestDigest)
|
||||
defer undo()
|
||||
|
||||
alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", " ")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON"))
|
||||
|
||||
s.reg.WriteBlobContents(c, manifestDigest, alteredManifestBlob)
|
||||
|
||||
// Now try pulling that image by digest. We should get an error about
|
||||
// digest verification for the manifest digest.
|
||||
|
||||
// Pull from the registry using the <name>@<digest> reference.
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest)
|
||||
out, exitStatus, _ := dockerCmdWithError("pull", imageReference)
|
||||
c.Assert(exitStatus, checker.Not(check.Equals), 0)
|
||||
|
||||
expectedErrorMsg := fmt.Sprintf("manifest verification failed for digest %s", manifestDigest)
|
||||
c.Assert(out, checker.Contains, expectedErrorMsg)
|
||||
}
|
||||
|
||||
// TestPullFailsWithAlteredManifest tests that a `docker pull` fails when
|
||||
// we have modified a manifest blob and its digest cannot be verified.
|
||||
// This is the schema1 version of the test.
|
||||
func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
manifestDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
// Load the target manifest blob.
|
||||
manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
|
||||
|
||||
var imgManifest schema1.Manifest
|
||||
err = json.Unmarshal(manifestBlob, &imgManifest)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to decode image manifest from blob"))
|
||||
|
||||
// Change a layer in the manifest.
|
||||
imgManifest.FSLayers[0] = schema1.FSLayer{
|
||||
BlobSum: digest.Digest("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"),
|
||||
}
|
||||
|
||||
// Move the existing data file aside, so that we can replace it with a
|
||||
// malicious blob of data. NOTE: we defer the returned undo func.
|
||||
undo := s.reg.TempMoveBlobData(c, manifestDigest)
|
||||
defer undo()
|
||||
|
||||
alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", " ")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON"))
|
||||
|
||||
s.reg.WriteBlobContents(c, manifestDigest, alteredManifestBlob)
|
||||
|
||||
// Now try pulling that image by digest. We should get an error about
|
||||
// digest verification for the manifest digest.
|
||||
|
||||
// Pull from the registry using the <name>@<digest> reference.
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest)
|
||||
out, exitStatus, _ := dockerCmdWithError("pull", imageReference)
|
||||
c.Assert(exitStatus, checker.Not(check.Equals), 0)
|
||||
|
||||
expectedErrorMsg := fmt.Sprintf("image verification failed for digest %s", manifestDigest)
|
||||
c.Assert(out, checker.Contains, expectedErrorMsg)
|
||||
}
|
||||
|
||||
// TestPullFailsWithAlteredLayer tests that a `docker pull` fails when
|
||||
// we have modified a layer blob and its digest cannot be verified.
|
||||
// This is the schema2 version of the test.
|
||||
func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
manifestDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Load the target manifest blob.
|
||||
manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
|
||||
|
||||
var imgManifest schema2.Manifest
|
||||
err = json.Unmarshal(manifestBlob, &imgManifest)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Next, get the digest of one of the layers from the manifest.
|
||||
targetLayerDigest := imgManifest.Layers[0].Digest
|
||||
|
||||
// Move the existing data file aside, so that we can replace it with a
|
||||
// malicious blob of data. NOTE: we defer the returned undo func.
|
||||
undo := s.reg.TempMoveBlobData(c, targetLayerDigest)
|
||||
defer undo()
|
||||
|
||||
// Now make a fake data blob in this directory.
|
||||
s.reg.WriteBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for."))
|
||||
|
||||
// Now try pulling that image by digest. We should get an error about
|
||||
// digest verification for the target layer digest.
|
||||
|
||||
// Remove distribution cache to force a re-pull of the blobs
|
||||
if err := os.RemoveAll(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "image", s.d.StorageDriver(), "distribution")); err != nil {
|
||||
c.Fatalf("error clearing distribution cache: %v", err)
|
||||
}
|
||||
|
||||
// Pull from the registry using the <name>@<digest> reference.
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest)
|
||||
out, exitStatus, _ := dockerCmdWithError("pull", imageReference)
|
||||
c.Assert(exitStatus, checker.Not(check.Equals), 0, check.Commentf("expected a non-zero exit status"))
|
||||
|
||||
expectedErrorMsg := fmt.Sprintf("filesystem layer verification failed for digest %s", targetLayerDigest)
|
||||
c.Assert(out, checker.Contains, expectedErrorMsg, check.Commentf("expected error message in output: %s", out))
|
||||
}
|
||||
|
||||
// TestPullFailsWithAlteredLayer tests that a `docker pull` fails when
|
||||
// we have modified a layer blob and its digest cannot be verified.
|
||||
// This is the schema1 version of the test.
|
||||
func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
manifestDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Load the target manifest blob.
|
||||
manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
|
||||
|
||||
var imgManifest schema1.Manifest
|
||||
err = json.Unmarshal(manifestBlob, &imgManifest)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Next, get the digest of one of the layers from the manifest.
|
||||
targetLayerDigest := imgManifest.FSLayers[0].BlobSum
|
||||
|
||||
// Move the existing data file aside, so that we can replace it with a
|
||||
// malicious blob of data. NOTE: we defer the returned undo func.
|
||||
undo := s.reg.TempMoveBlobData(c, targetLayerDigest)
|
||||
defer undo()
|
||||
|
||||
// Now make a fake data blob in this directory.
|
||||
s.reg.WriteBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for."))
|
||||
|
||||
// Now try pulling that image by digest. We should get an error about
|
||||
// digest verification for the target layer digest.
|
||||
|
||||
// Remove distribution cache to force a re-pull of the blobs
|
||||
if err := os.RemoveAll(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "image", s.d.StorageDriver(), "distribution")); err != nil {
|
||||
c.Fatalf("error clearing distribution cache: %v", err)
|
||||
}
|
||||
|
||||
// Pull from the registry using the <name>@<digest> reference.
|
||||
imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest)
|
||||
out, exitStatus, _ := dockerCmdWithError("pull", imageReference)
|
||||
c.Assert(exitStatus, checker.Not(check.Equals), 0, check.Commentf("expected a non-zero exit status"))
|
||||
|
||||
expectedErrorMsg := fmt.Sprintf("filesystem layer verification failed for digest %s", targetLayerDigest)
|
||||
c.Assert(out, checker.Contains, expectedErrorMsg, check.Commentf("expected error message in output: %s", out))
|
||||
}
|
167
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_commit_test.go
generated
vendored
Normal file
167
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_commit_test.go
generated
vendored
Normal file
|
@ -0,0 +1,167 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestCommitAfterContainerIsDone(c *check.C) {
|
||||
out := cli.DockerCmd(c, "run", "-i", "-a", "stdin", "busybox", "echo", "foo").Combined()
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
cli.DockerCmd(c, "wait", cleanedContainerID)
|
||||
|
||||
out = cli.DockerCmd(c, "commit", cleanedContainerID).Combined()
|
||||
|
||||
cleanedImageID := strings.TrimSpace(out)
|
||||
|
||||
cli.DockerCmd(c, "inspect", cleanedImageID)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCommitWithoutPause(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-i", "-a", "stdin", "busybox", "echo", "foo")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "wait", cleanedContainerID)
|
||||
|
||||
out, _ = dockerCmd(c, "commit", "-p=false", cleanedContainerID)
|
||||
|
||||
cleanedImageID := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "inspect", cleanedImageID)
|
||||
}
|
||||
|
||||
//test commit a paused container should not unpause it after commit
|
||||
func (s *DockerSuite) TestCommitPausedContainer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-i", "-d", "busybox")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "pause", cleanedContainerID)
|
||||
dockerCmd(c, "commit", cleanedContainerID)
|
||||
|
||||
out = inspectField(c, cleanedContainerID, "State.Paused")
|
||||
// commit should not unpause a paused container
|
||||
c.Assert(out, checker.Contains, "true")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCommitNewFile(c *check.C) {
|
||||
dockerCmd(c, "run", "--name", "committer", "busybox", "/bin/sh", "-c", "echo koye > /foo")
|
||||
|
||||
imageID, _ := dockerCmd(c, "commit", "committer")
|
||||
imageID = strings.TrimSpace(imageID)
|
||||
|
||||
out, _ := dockerCmd(c, "run", imageID, "cat", "/foo")
|
||||
actual := strings.TrimSpace(out)
|
||||
c.Assert(actual, checker.Equals, "koye")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCommitHardlink(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
firstOutput, _ := dockerCmd(c, "run", "-t", "--name", "hardlinks", "busybox", "sh", "-c", "touch file1 && ln file1 file2 && ls -di file1 file2")
|
||||
|
||||
chunks := strings.Split(strings.TrimSpace(firstOutput), " ")
|
||||
inode := chunks[0]
|
||||
chunks = strings.SplitAfterN(strings.TrimSpace(firstOutput), " ", 2)
|
||||
c.Assert(chunks[1], checker.Contains, chunks[0], check.Commentf("Failed to create hardlink in a container. Expected to find %q in %q", inode, chunks[1:]))
|
||||
|
||||
imageID, _ := dockerCmd(c, "commit", "hardlinks", "hardlinks")
|
||||
imageID = strings.TrimSpace(imageID)
|
||||
|
||||
secondOutput, _ := dockerCmd(c, "run", "-t", imageID, "ls", "-di", "file1", "file2")
|
||||
|
||||
chunks = strings.Split(strings.TrimSpace(secondOutput), " ")
|
||||
inode = chunks[0]
|
||||
chunks = strings.SplitAfterN(strings.TrimSpace(secondOutput), " ", 2)
|
||||
c.Assert(chunks[1], checker.Contains, chunks[0], check.Commentf("Failed to create hardlink in a container. Expected to find %q in %q", inode, chunks[1:]))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCommitTTY(c *check.C) {
|
||||
dockerCmd(c, "run", "-t", "--name", "tty", "busybox", "/bin/ls")
|
||||
|
||||
imageID, _ := dockerCmd(c, "commit", "tty", "ttytest")
|
||||
imageID = strings.TrimSpace(imageID)
|
||||
|
||||
dockerCmd(c, "run", imageID, "/bin/ls")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCommitWithHostBindMount(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "--name", "bind-commit", "-v", "/dev/null:/winning", "busybox", "true")
|
||||
|
||||
imageID, _ := dockerCmd(c, "commit", "bind-commit", "bindtest")
|
||||
imageID = strings.TrimSpace(imageID)
|
||||
|
||||
dockerCmd(c, "run", imageID, "true")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCommitChange(c *check.C) {
|
||||
dockerCmd(c, "run", "--name", "test", "busybox", "true")
|
||||
|
||||
imageID, _ := dockerCmd(c, "commit",
|
||||
"--change", "EXPOSE 8080",
|
||||
"--change", "ENV DEBUG true",
|
||||
"--change", "ENV test 1",
|
||||
"--change", "ENV PATH /foo",
|
||||
"--change", "LABEL foo bar",
|
||||
"--change", "CMD [\"/bin/sh\"]",
|
||||
"--change", "WORKDIR /opt",
|
||||
"--change", "ENTRYPOINT [\"/bin/sh\"]",
|
||||
"--change", "USER testuser",
|
||||
"--change", "VOLUME /var/lib/docker",
|
||||
"--change", "ONBUILD /usr/local/bin/python-build --dir /app/src",
|
||||
"test", "test-commit")
|
||||
imageID = strings.TrimSpace(imageID)
|
||||
|
||||
expectedEnv := "[DEBUG=true test=1 PATH=/foo]"
|
||||
// bug fixed in 1.36, add min APi >= 1.36 requirement
|
||||
// PR record https://github.com/moby/moby/pull/35582
|
||||
if versions.GreaterThan(testEnv.DaemonAPIVersion(), "1.35") && testEnv.OSType != "windows" {
|
||||
// The ordering here is due to `PATH` being overridden from the container's
|
||||
// ENV. On windows, the container doesn't have a `PATH` ENV variable so
|
||||
// the ordering is the same as the cli.
|
||||
expectedEnv = "[PATH=/foo DEBUG=true test=1]"
|
||||
}
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
prefix = strings.ToUpper(prefix) // Force C: as that's how WORKDIR is normalized on Windows
|
||||
expected := map[string]string{
|
||||
"Config.ExposedPorts": "map[8080/tcp:{}]",
|
||||
"Config.Env": expectedEnv,
|
||||
"Config.Labels": "map[foo:bar]",
|
||||
"Config.Cmd": "[/bin/sh]",
|
||||
"Config.WorkingDir": prefix + slash + "opt",
|
||||
"Config.Entrypoint": "[/bin/sh]",
|
||||
"Config.User": "testuser",
|
||||
"Config.Volumes": "map[/var/lib/docker:{}]",
|
||||
"Config.OnBuild": "[/usr/local/bin/python-build --dir /app/src]",
|
||||
}
|
||||
|
||||
for conf, value := range expected {
|
||||
res := inspectField(c, imageID, conf)
|
||||
if res != value {
|
||||
c.Errorf("%s('%s'), expected %s", conf, res, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCommitChangeLabels(c *check.C) {
|
||||
dockerCmd(c, "run", "--name", "test", "--label", "some=label", "busybox", "true")
|
||||
|
||||
imageID, _ := dockerCmd(c, "commit",
|
||||
"--change", "LABEL some=label2",
|
||||
"test", "test-commit")
|
||||
imageID = strings.TrimSpace(imageID)
|
||||
|
||||
c.Assert(inspectField(c, imageID, "Config.Labels"), checker.Equals, "map[some:label2]")
|
||||
// check that container labels didn't change
|
||||
c.Assert(inspectField(c, "test", "Config.Labels"), checker.Equals, "map[some:label]")
|
||||
}
|
33
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_config_create_test.go
generated
vendored
Normal file
33
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_config_create_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) TestConfigCreateWithFile(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
testFile, err := ioutil.TempFile("", "configCreateTest")
|
||||
c.Assert(err, checker.IsNil) // ensure temp file is created
|
||||
defer os.Remove(testFile.Name())
|
||||
|
||||
testData := "TESTINGDATA"
|
||||
_, err = testFile.Write([]byte(testData))
|
||||
c.Assert(err, checker.IsNil) // ensure temp file is written
|
||||
|
||||
testName := "test_config"
|
||||
out, err := d.Cmd("config", "create", testName, testFile.Name())
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
|
||||
id := strings.TrimSpace(out)
|
||||
config := d.GetConfig(c, id)
|
||||
c.Assert(config.Spec.Name, checker.Equals, testName)
|
||||
}
|
399
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_cp_from_container_test.go
generated
vendored
Normal file
399
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_cp_from_container_test.go
generated
vendored
Normal file
|
@ -0,0 +1,399 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// Try all of the test cases from the archive package which implements the
|
||||
// internals of `docker cp` and ensure that the behavior matches when actually
|
||||
// copying to and from containers.
|
||||
|
||||
// Basic assumptions about SRC and DST:
|
||||
// 1. SRC must exist.
|
||||
// 2. If SRC ends with a trailing separator, it must be a directory.
|
||||
// 3. DST parent directory must exist.
|
||||
// 4. If DST exists as a file, it must not end with a trailing separator.
|
||||
|
||||
// Check that copying from a container to a local symlink copies to the symlink
|
||||
// target and does not overwrite the local symlink itself.
|
||||
// TODO: move to docker/cli and/or integration/container/copy_test.go
|
||||
func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{addContent: true})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-err-dst-not-dir")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
// First, copy a file from the container to a symlink to a file. This
|
||||
// should overwrite the symlink target contents with the source contents.
|
||||
srcPath := containerCpPath(containerID, "/file2")
|
||||
dstPath := cpPath(tmpDir, "symlinkToFile1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// The symlink should not have been modified.
|
||||
c.Assert(symlinkTargetEquals(c, dstPath, "file1"), checker.IsNil)
|
||||
|
||||
// The file should have the contents of "file2" now.
|
||||
c.Assert(fileContentEquals(c, cpPath(tmpDir, "file1"), "file2\n"), checker.IsNil)
|
||||
|
||||
// Next, copy a file from the container to a symlink to a directory. This
|
||||
// should copy the file into the symlink target directory.
|
||||
dstPath = cpPath(tmpDir, "symlinkToDir1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// The symlink should not have been modified.
|
||||
c.Assert(symlinkTargetEquals(c, dstPath, "dir1"), checker.IsNil)
|
||||
|
||||
// The file should have the contents of "file2" now.
|
||||
c.Assert(fileContentEquals(c, cpPath(tmpDir, "file2"), "file2\n"), checker.IsNil)
|
||||
|
||||
// Next, copy a file from the container to a symlink to a file that does
|
||||
// not exist (a broken symlink). This should create the target file with
|
||||
// the contents of the source file.
|
||||
dstPath = cpPath(tmpDir, "brokenSymlinkToFileX")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// The symlink should not have been modified.
|
||||
c.Assert(symlinkTargetEquals(c, dstPath, "fileX"), checker.IsNil)
|
||||
|
||||
// The file should have the contents of "file2" now.
|
||||
c.Assert(fileContentEquals(c, cpPath(tmpDir, "fileX"), "file2\n"), checker.IsNil)
|
||||
|
||||
// Next, copy a directory from the container to a symlink to a local
|
||||
// directory. This should copy the directory into the symlink target
|
||||
// directory and not modify the symlink.
|
||||
srcPath = containerCpPath(containerID, "/dir2")
|
||||
dstPath = cpPath(tmpDir, "symlinkToDir1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// The symlink should not have been modified.
|
||||
c.Assert(symlinkTargetEquals(c, dstPath, "dir1"), checker.IsNil)
|
||||
|
||||
// The directory should now contain a copy of "dir2".
|
||||
c.Assert(fileContentEquals(c, cpPath(tmpDir, "dir1/dir2/file2-1"), "file2-1\n"), checker.IsNil)
|
||||
|
||||
// Next, copy a directory from the container to a symlink to a local
|
||||
// directory that does not exist (a broken symlink). This should create
|
||||
// the target as a directory with the contents of the source directory. It
|
||||
// should not modify the symlink.
|
||||
dstPath = cpPath(tmpDir, "brokenSymlinkToDirX")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// The symlink should not have been modified.
|
||||
c.Assert(symlinkTargetEquals(c, dstPath, "dirX"), checker.IsNil)
|
||||
|
||||
// The "dirX" directory should now be a copy of "dir2".
|
||||
c.Assert(fileContentEquals(c, cpPath(tmpDir, "dirX/file2-1"), "file2-1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// Possibilities are reduced to the remaining 10 cases:
|
||||
//
|
||||
// case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action
|
||||
// ===================================================================================================
|
||||
// A | no | - | no | - | no | create file
|
||||
// B | no | - | no | - | yes | error
|
||||
// C | no | - | yes | no | - | overwrite file
|
||||
// D | no | - | yes | yes | - | create file in dst dir
|
||||
// E | yes | no | no | - | - | create dir, copy contents
|
||||
// F | yes | no | yes | no | - | error
|
||||
// G | yes | no | yes | yes | - | copy dir and contents
|
||||
// H | yes | yes | no | - | - | create dir, copy contents
|
||||
// I | yes | yes | yes | no | - | error
|
||||
// J | yes | yes | yes | yes | - | copy dir contents
|
||||
//
|
||||
|
||||
// A. SRC specifies a file and DST (no trailing path separator) doesn't
|
||||
// exist. This should create a file with the name DST and copy the
|
||||
// contents of the source file into it.
|
||||
func (s *DockerSuite) TestCpFromCaseA(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-case-a")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
srcPath := containerCpPath(containerID, "/root/file1")
|
||||
dstPath := cpPath(tmpDir, "itWorks.txt")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// B. SRC specifies a file and DST (with trailing path separator) doesn't
|
||||
// exist. This should cause an error because the copy operation cannot
|
||||
// create a directory when copying a single file.
|
||||
func (s *DockerSuite) TestCpFromCaseB(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{addContent: true})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-case-b")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
srcPath := containerCpPath(containerID, "/file1")
|
||||
dstDir := cpPathTrailingSep(tmpDir, "testDir")
|
||||
|
||||
err := runDockerCp(c, srcPath, dstDir, nil)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExists error, but got %T: %s", err, err))
|
||||
}
|
||||
|
||||
// C. SRC specifies a file and DST exists as a file. This should overwrite
|
||||
// the file at DST with the contents of the source file.
|
||||
func (s *DockerSuite) TestCpFromCaseC(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-case-c")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcPath := containerCpPath(containerID, "/root/file1")
|
||||
dstPath := cpPath(tmpDir, "file2")
|
||||
|
||||
// Ensure the local file starts with different content.
|
||||
c.Assert(fileContentEquals(c, dstPath, "file2\n"), checker.IsNil)
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// D. SRC specifies a file and DST exists as a directory. This should place
|
||||
// a copy of the source file inside it using the basename from SRC. Ensure
|
||||
// this works whether DST has a trailing path separator or not.
|
||||
func (s *DockerSuite) TestCpFromCaseD(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{addContent: true})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-case-d")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcPath := containerCpPath(containerID, "/file1")
|
||||
dstDir := cpPath(tmpDir, "dir1")
|
||||
dstPath := filepath.Join(dstDir, "file1")
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
_, err := os.Stat(dstPath)
|
||||
c.Assert(os.IsNotExist(err), checker.True, check.Commentf("did not expect dstPath %q to exist", dstPath))
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil)
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
// unable to remove dstDir
|
||||
c.Assert(os.RemoveAll(dstDir), checker.IsNil)
|
||||
|
||||
// unable to make dstDir
|
||||
c.Assert(os.MkdirAll(dstDir, os.FileMode(0755)), checker.IsNil)
|
||||
|
||||
dstDir = cpPathTrailingSep(tmpDir, "dir1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// E. SRC specifies a directory and DST does not exist. This should create a
|
||||
// directory at DST and copy the contents of the SRC directory into the DST
|
||||
// directory. Ensure this works whether DST has a trailing path separator or
|
||||
// not.
|
||||
func (s *DockerSuite) TestCpFromCaseE(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{addContent: true})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-case-e")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
srcDir := containerCpPath(containerID, "dir1")
|
||||
dstDir := cpPath(tmpDir, "testDir")
|
||||
dstPath := filepath.Join(dstDir, "file1-1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
// unable to remove dstDir
|
||||
c.Assert(os.RemoveAll(dstDir), checker.IsNil)
|
||||
|
||||
dstDir = cpPathTrailingSep(tmpDir, "testDir")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// F. SRC specifies a directory and DST exists as a file. This should cause an
|
||||
// error as it is not possible to overwrite a file with a directory.
|
||||
func (s *DockerSuite) TestCpFromCaseF(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-case-f")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcDir := containerCpPath(containerID, "/root/dir1")
|
||||
dstFile := cpPath(tmpDir, "file1")
|
||||
|
||||
err := runDockerCp(c, srcDir, dstFile, nil)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
|
||||
}
|
||||
|
||||
// G. SRC specifies a directory and DST exists as a directory. This should copy
|
||||
// the SRC directory and all its contents to the DST directory. Ensure this
|
||||
// works whether DST has a trailing path separator or not.
|
||||
func (s *DockerSuite) TestCpFromCaseG(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-case-g")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcDir := containerCpPath(containerID, "/root/dir1")
|
||||
dstDir := cpPath(tmpDir, "dir2")
|
||||
resultDir := filepath.Join(dstDir, "dir1")
|
||||
dstPath := filepath.Join(resultDir, "file1-1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
// unable to remove dstDir
|
||||
c.Assert(os.RemoveAll(dstDir), checker.IsNil)
|
||||
|
||||
// unable to make dstDir
|
||||
c.Assert(os.MkdirAll(dstDir, os.FileMode(0755)), checker.IsNil)
|
||||
|
||||
dstDir = cpPathTrailingSep(tmpDir, "dir2")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// H. SRC specifies a directory's contents only and DST does not exist. This
|
||||
// should create a directory at DST and copy the contents of the SRC
|
||||
// directory (but not the directory itself) into the DST directory. Ensure
|
||||
// this works whether DST has a trailing path separator or not.
|
||||
func (s *DockerSuite) TestCpFromCaseH(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{addContent: true})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-case-h")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
srcDir := containerCpPathTrailingSep(containerID, "dir1") + "."
|
||||
dstDir := cpPath(tmpDir, "testDir")
|
||||
dstPath := filepath.Join(dstDir, "file1-1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
// unable to remove resultDir
|
||||
c.Assert(os.RemoveAll(dstDir), checker.IsNil)
|
||||
|
||||
dstDir = cpPathTrailingSep(tmpDir, "testDir")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// I. SRC specifies a directory's contents only and DST exists as a file. This
|
||||
// should cause an error as it is not possible to overwrite a file with a
|
||||
// directory.
|
||||
func (s *DockerSuite) TestCpFromCaseI(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-case-i")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcDir := containerCpPathTrailingSep(containerID, "/root/dir1") + "."
|
||||
dstFile := cpPath(tmpDir, "file1")
|
||||
|
||||
err := runDockerCp(c, srcDir, dstFile, nil)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
|
||||
}
|
||||
|
||||
// J. SRC specifies a directory's contents only and DST exists as a directory.
|
||||
// This should copy the contents of the SRC directory (but not the directory
|
||||
// itself) into the DST directory. Ensure this works whether DST has a
|
||||
// trailing path separator or not.
|
||||
func (s *DockerSuite) TestCpFromCaseJ(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-from-case-j")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcDir := containerCpPathTrailingSep(containerID, "/root/dir1") + "."
|
||||
dstDir := cpPath(tmpDir, "dir2")
|
||||
dstPath := filepath.Join(dstDir, "file1-1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
// unable to remove dstDir
|
||||
c.Assert(os.RemoveAll(dstDir), checker.IsNil)
|
||||
|
||||
// unable to make dstDir
|
||||
c.Assert(os.MkdirAll(dstDir, os.FileMode(0755)), checker.IsNil)
|
||||
|
||||
dstDir = cpPathTrailingSep(tmpDir, "dir2")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
|
||||
}
|
667
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_cp_test.go
generated
vendored
Normal file
667
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_cp_test.go
generated
vendored
Normal file
|
@ -0,0 +1,667 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
const (
|
||||
cpTestPathParent = "/some"
|
||||
cpTestPath = "/some/path"
|
||||
cpTestName = "test"
|
||||
cpFullPath = "/some/path/test"
|
||||
|
||||
cpContainerContents = "holla, i am the container"
|
||||
cpHostContents = "hello, i am the host"
|
||||
)
|
||||
|
||||
// Ensure that an all-local path case returns an error.
|
||||
func (s *DockerSuite) TestCpLocalOnly(c *check.C) {
|
||||
err := runDockerCp(c, "foo", "bar", nil)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
c.Assert(err.Error(), checker.Contains, "must specify at least one container source")
|
||||
}
|
||||
|
||||
// Test for #5656
|
||||
// Check that garbage paths don't escape the container's rootfs
|
||||
func (s *DockerSuite) TestCpGarbagePath(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
c.Assert(os.MkdirAll(cpTestPath, os.ModeDir), checker.IsNil)
|
||||
|
||||
hostFile, err := os.Create(cpFullPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer hostFile.Close()
|
||||
defer os.RemoveAll(cpTestPathParent)
|
||||
|
||||
fmt.Fprintf(hostFile, "%s", cpHostContents)
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "docker-integration")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
tmpname := filepath.Join(tmpdir, cpTestName)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
path := path.Join("../../../../../../../../../../../../", cpFullPath)
|
||||
|
||||
dockerCmd(c, "cp", containerID+":"+path, tmpdir)
|
||||
|
||||
file, _ := os.Open(tmpname)
|
||||
defer file.Close()
|
||||
|
||||
test, err := ioutil.ReadAll(file)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// output matched host file -- garbage path can escape container rootfs
|
||||
c.Assert(string(test), checker.Not(checker.Equals), cpHostContents)
|
||||
|
||||
// output doesn't match the input for garbage path
|
||||
c.Assert(string(test), checker.Equals, cpContainerContents)
|
||||
}
|
||||
|
||||
// Check that relative paths are relative to the container's rootfs
|
||||
func (s *DockerSuite) TestCpRelativePath(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
c.Assert(os.MkdirAll(cpTestPath, os.ModeDir), checker.IsNil)
|
||||
|
||||
hostFile, err := os.Create(cpFullPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer hostFile.Close()
|
||||
defer os.RemoveAll(cpTestPathParent)
|
||||
|
||||
fmt.Fprintf(hostFile, "%s", cpHostContents)
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "docker-integration")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
tmpname := filepath.Join(tmpdir, cpTestName)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
var relPath string
|
||||
if path.IsAbs(cpFullPath) {
|
||||
// normally this is `filepath.Rel("/", cpFullPath)` but we cannot
|
||||
// get this unix-path manipulation on windows with filepath.
|
||||
relPath = cpFullPath[1:]
|
||||
}
|
||||
c.Assert(path.IsAbs(cpFullPath), checker.True, check.Commentf("path %s was assumed to be an absolute path", cpFullPath))
|
||||
|
||||
dockerCmd(c, "cp", containerID+":"+relPath, tmpdir)
|
||||
|
||||
file, _ := os.Open(tmpname)
|
||||
defer file.Close()
|
||||
|
||||
test, err := ioutil.ReadAll(file)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// output matched host file -- relative path can escape container rootfs
|
||||
c.Assert(string(test), checker.Not(checker.Equals), cpHostContents)
|
||||
|
||||
// output doesn't match the input for relative path
|
||||
c.Assert(string(test), checker.Equals, cpContainerContents)
|
||||
}
|
||||
|
||||
// Check that absolute paths are relative to the container's rootfs
|
||||
func (s *DockerSuite) TestCpAbsolutePath(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
c.Assert(os.MkdirAll(cpTestPath, os.ModeDir), checker.IsNil)
|
||||
|
||||
hostFile, err := os.Create(cpFullPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer hostFile.Close()
|
||||
defer os.RemoveAll(cpTestPathParent)
|
||||
|
||||
fmt.Fprintf(hostFile, "%s", cpHostContents)
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "docker-integration")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
tmpname := filepath.Join(tmpdir, cpTestName)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
path := cpFullPath
|
||||
|
||||
dockerCmd(c, "cp", containerID+":"+path, tmpdir)
|
||||
|
||||
file, _ := os.Open(tmpname)
|
||||
defer file.Close()
|
||||
|
||||
test, err := ioutil.ReadAll(file)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// output matched host file -- absolute path can escape container rootfs
|
||||
c.Assert(string(test), checker.Not(checker.Equals), cpHostContents)
|
||||
|
||||
// output doesn't match the input for absolute path
|
||||
c.Assert(string(test), checker.Equals, cpContainerContents)
|
||||
}
|
||||
|
||||
// Test for #5619
|
||||
// Check that absolute symlinks are still relative to the container's rootfs
|
||||
func (s *DockerSuite) TestCpAbsoluteSymlink(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpFullPath+" container_path")
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
c.Assert(os.MkdirAll(cpTestPath, os.ModeDir), checker.IsNil)
|
||||
|
||||
hostFile, err := os.Create(cpFullPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer hostFile.Close()
|
||||
defer os.RemoveAll(cpTestPathParent)
|
||||
|
||||
fmt.Fprintf(hostFile, "%s", cpHostContents)
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "docker-integration")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
tmpname := filepath.Join(tmpdir, "container_path")
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
path := path.Join("/", "container_path")
|
||||
|
||||
dockerCmd(c, "cp", containerID+":"+path, tmpdir)
|
||||
|
||||
// We should have copied a symlink *NOT* the file itself!
|
||||
linkTarget, err := os.Readlink(tmpname)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(linkTarget, checker.Equals, filepath.FromSlash(cpFullPath))
|
||||
}
|
||||
|
||||
// Check that symlinks to a directory behave as expected when copying one from
|
||||
// a container.
|
||||
func (s *DockerSuite) TestCpFromSymlinkToDirectory(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPathParent+" /dir_link")
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
testDir, err := ioutil.TempDir("", "test-cp-from-symlink-to-dir-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(testDir)
|
||||
|
||||
// This copy command should copy the symlink, not the target, into the
|
||||
// temporary directory.
|
||||
dockerCmd(c, "cp", containerID+":"+"/dir_link", testDir)
|
||||
|
||||
expectedPath := filepath.Join(testDir, "dir_link")
|
||||
linkTarget, err := os.Readlink(expectedPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(linkTarget, checker.Equals, filepath.FromSlash(cpTestPathParent))
|
||||
|
||||
os.Remove(expectedPath)
|
||||
|
||||
// This copy command should resolve the symlink (note the trailing
|
||||
// separator), copying the target into the temporary directory.
|
||||
dockerCmd(c, "cp", containerID+":"+"/dir_link/", testDir)
|
||||
|
||||
// It *should not* have copied the directory using the target's name, but
|
||||
// used the given name instead.
|
||||
unexpectedPath := filepath.Join(testDir, cpTestPathParent)
|
||||
stat, err := os.Lstat(unexpectedPath)
|
||||
if err == nil {
|
||||
out = fmt.Sprintf("target name was copied: %q - %q", stat.Mode(), stat.Name())
|
||||
}
|
||||
c.Assert(err, checker.NotNil, check.Commentf("%s", out))
|
||||
|
||||
// It *should* have copied the directory using the asked name "dir_link".
|
||||
stat, err = os.Lstat(expectedPath)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to stat resource at %q", expectedPath))
|
||||
|
||||
c.Assert(stat.IsDir(), checker.True, check.Commentf("should have copied a directory but got %q instead", stat.Mode()))
|
||||
}
|
||||
|
||||
// Check that symlinks to a directory behave as expected when copying one to a
|
||||
// container.
|
||||
func (s *DockerSuite) TestCpToSymlinkToDirectory(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon) // Requires local volume mount bind.
|
||||
|
||||
testVol, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(testVol)
|
||||
|
||||
// Create a test container with a local volume. We will test by copying
|
||||
// to the volume path in the container which we can then verify locally.
|
||||
out, _ := dockerCmd(c, "create", "-v", testVol+":/testVol", "busybox")
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
// Create a temp directory to hold a test file nested in a directory.
|
||||
testDir, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(testDir)
|
||||
|
||||
// This file will be at "/testDir/some/path/test" and will be copied into
|
||||
// the test volume later.
|
||||
hostTestFilename := filepath.Join(testDir, cpFullPath)
|
||||
c.Assert(os.MkdirAll(filepath.Dir(hostTestFilename), os.FileMode(0700)), checker.IsNil)
|
||||
c.Assert(ioutil.WriteFile(hostTestFilename, []byte(cpHostContents), os.FileMode(0600)), checker.IsNil)
|
||||
|
||||
// Now create another temp directory to hold a symlink to the
|
||||
// "/testDir/some" directory.
|
||||
linkDir, err := ioutil.TempDir("", "test-cp-to-symlink-to-dir-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(linkDir)
|
||||
|
||||
// Then symlink "/linkDir/dir_link" to "/testdir/some".
|
||||
linkTarget := filepath.Join(testDir, cpTestPathParent)
|
||||
localLink := filepath.Join(linkDir, "dir_link")
|
||||
c.Assert(os.Symlink(linkTarget, localLink), checker.IsNil)
|
||||
|
||||
// Now copy that symlink into the test volume in the container.
|
||||
dockerCmd(c, "cp", localLink, containerID+":/testVol")
|
||||
|
||||
// This copy command should have copied the symlink *not* the target.
|
||||
expectedPath := filepath.Join(testVol, "dir_link")
|
||||
actualLinkTarget, err := os.Readlink(expectedPath)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to read symlink at %q", expectedPath))
|
||||
|
||||
c.Assert(actualLinkTarget, checker.Equals, linkTarget)
|
||||
|
||||
// Good, now remove that copied link for the next test.
|
||||
os.Remove(expectedPath)
|
||||
|
||||
// This copy command should resolve the symlink (note the trailing
|
||||
// separator), copying the target into the test volume directory in the
|
||||
// container.
|
||||
dockerCmd(c, "cp", localLink+"/", containerID+":/testVol")
|
||||
|
||||
// It *should not* have copied the directory using the target's name, but
|
||||
// used the given name instead.
|
||||
unexpectedPath := filepath.Join(testVol, cpTestPathParent)
|
||||
stat, err := os.Lstat(unexpectedPath)
|
||||
if err == nil {
|
||||
out = fmt.Sprintf("target name was copied: %q - %q", stat.Mode(), stat.Name())
|
||||
}
|
||||
c.Assert(err, checker.NotNil, check.Commentf("%s", out))
|
||||
|
||||
// It *should* have copied the directory using the asked name "dir_link".
|
||||
stat, err = os.Lstat(expectedPath)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("unable to stat resource at %q", expectedPath))
|
||||
|
||||
c.Assert(stat.IsDir(), checker.True, check.Commentf("should have copied a directory but got %q instead", stat.Mode()))
|
||||
|
||||
// And this directory should contain the file copied from the host at the
|
||||
// expected location: "/testVol/dir_link/path/test"
|
||||
expectedFilepath := filepath.Join(testVol, "dir_link/path/test")
|
||||
fileContents, err := ioutil.ReadFile(expectedFilepath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(string(fileContents), checker.Equals, cpHostContents)
|
||||
}
|
||||
|
||||
// Test for #5619
|
||||
// Check that symlinks which are part of the resource path are still relative to the container's rootfs
|
||||
func (s *DockerSuite) TestCpSymlinkComponent(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpTestPath+" container_path")
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
c.Assert(os.MkdirAll(cpTestPath, os.ModeDir), checker.IsNil)
|
||||
|
||||
hostFile, err := os.Create(cpFullPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer hostFile.Close()
|
||||
defer os.RemoveAll(cpTestPathParent)
|
||||
|
||||
fmt.Fprintf(hostFile, "%s", cpHostContents)
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "docker-integration")
|
||||
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
tmpname := filepath.Join(tmpdir, cpTestName)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
path := path.Join("/", "container_path", cpTestName)
|
||||
|
||||
dockerCmd(c, "cp", containerID+":"+path, tmpdir)
|
||||
|
||||
file, _ := os.Open(tmpname)
|
||||
defer file.Close()
|
||||
|
||||
test, err := ioutil.ReadAll(file)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// output matched host file -- symlink path component can escape container rootfs
|
||||
c.Assert(string(test), checker.Not(checker.Equals), cpHostContents)
|
||||
|
||||
// output doesn't match the input for symlink path component
|
||||
c.Assert(string(test), checker.Equals, cpContainerContents)
|
||||
}
|
||||
|
||||
// Check that cp with unprivileged user doesn't return any error
|
||||
func (s *DockerSuite) TestCpUnprivilegedUser(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
testRequires(c, UnixCli) // uses chmod/su: not available on windows
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch "+cpTestName)
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "docker-integration")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
c.Assert(os.Chmod(tmpdir, 0777), checker.IsNil)
|
||||
|
||||
result := icmd.RunCommand("su", "unprivilegeduser", "-c",
|
||||
fmt.Sprintf("%s cp %s:%s %s", dockerBinary, containerID, cpTestName, tmpdir))
|
||||
result.Assert(c, icmd.Expected{})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCpSpecialFiles(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon)
|
||||
|
||||
outDir, err := ioutil.TempDir("", "cp-test-special-files")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(outDir)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "touch /foo")
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
// Copy actual /etc/resolv.conf
|
||||
dockerCmd(c, "cp", containerID+":/etc/resolv.conf", outDir)
|
||||
|
||||
expected := readContainerFile(c, containerID, "resolv.conf")
|
||||
actual, err := ioutil.ReadFile(outDir + "/resolv.conf")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Expected copied file to be duplicate of the container resolvconf
|
||||
c.Assert(bytes.Equal(actual, expected), checker.True)
|
||||
|
||||
// Copy actual /etc/hosts
|
||||
dockerCmd(c, "cp", containerID+":/etc/hosts", outDir)
|
||||
|
||||
expected = readContainerFile(c, containerID, "hosts")
|
||||
actual, err = ioutil.ReadFile(outDir + "/hosts")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Expected copied file to be duplicate of the container hosts
|
||||
c.Assert(bytes.Equal(actual, expected), checker.True)
|
||||
|
||||
// Copy actual /etc/resolv.conf
|
||||
dockerCmd(c, "cp", containerID+":/etc/hostname", outDir)
|
||||
|
||||
expected = readContainerFile(c, containerID, "hostname")
|
||||
actual, err = ioutil.ReadFile(outDir + "/hostname")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Expected copied file to be duplicate of the container resolvconf
|
||||
c.Assert(bytes.Equal(actual, expected), checker.True)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCpVolumePath(c *check.C) {
|
||||
// stat /tmp/cp-test-volumepath851508420/test gets permission denied for the user
|
||||
testRequires(c, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon)
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "cp-test-volumepath")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
outDir, err := ioutil.TempDir("", "cp-test-volumepath-out")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(outDir)
|
||||
_, err = os.Create(tmpDir + "/test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "-v", "/foo", "-v", tmpDir+"/test:/test", "-v", tmpDir+":/baz", "busybox", "/bin/sh", "-c", "touch /foo/bar")
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
// Copy actual volume path
|
||||
dockerCmd(c, "cp", containerID+":/foo", outDir)
|
||||
|
||||
stat, err := os.Stat(outDir + "/foo")
|
||||
c.Assert(err, checker.IsNil)
|
||||
// expected copied content to be dir
|
||||
c.Assert(stat.IsDir(), checker.True)
|
||||
stat, err = os.Stat(outDir + "/foo/bar")
|
||||
c.Assert(err, checker.IsNil)
|
||||
// Expected file `bar` to be a file
|
||||
c.Assert(stat.IsDir(), checker.False)
|
||||
|
||||
// Copy file nested in volume
|
||||
dockerCmd(c, "cp", containerID+":/foo/bar", outDir)
|
||||
|
||||
stat, err = os.Stat(outDir + "/bar")
|
||||
c.Assert(err, checker.IsNil)
|
||||
// Expected file `bar` to be a file
|
||||
c.Assert(stat.IsDir(), checker.False)
|
||||
|
||||
// Copy Bind-mounted dir
|
||||
dockerCmd(c, "cp", containerID+":/baz", outDir)
|
||||
stat, err = os.Stat(outDir + "/baz")
|
||||
c.Assert(err, checker.IsNil)
|
||||
// Expected `baz` to be a dir
|
||||
c.Assert(stat.IsDir(), checker.True)
|
||||
|
||||
// Copy file nested in bind-mounted dir
|
||||
dockerCmd(c, "cp", containerID+":/baz/test", outDir)
|
||||
fb, err := ioutil.ReadFile(outDir + "/baz/test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
fb2, err := ioutil.ReadFile(tmpDir + "/test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
// Expected copied file to be duplicate of bind-mounted file
|
||||
c.Assert(bytes.Equal(fb, fb2), checker.True)
|
||||
|
||||
// Copy bind-mounted file
|
||||
dockerCmd(c, "cp", containerID+":/test", outDir)
|
||||
fb, err = ioutil.ReadFile(outDir + "/test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
fb2, err = ioutil.ReadFile(tmpDir + "/test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
// Expected copied file to be duplicate of bind-mounted file
|
||||
c.Assert(bytes.Equal(fb, fb2), checker.True)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCpToDot(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "docker-integration")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
cwd, err := os.Getwd()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.Chdir(cwd)
|
||||
c.Assert(os.Chdir(tmpdir), checker.IsNil)
|
||||
dockerCmd(c, "cp", containerID+":/test", ".")
|
||||
content, err := ioutil.ReadFile("./test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(content), checker.Equals, "lololol\n")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCpToStdout(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
out, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "cp", containerID+":/test", "-"),
|
||||
exec.Command("tar", "-vtf", "-"))
|
||||
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(out, checker.Contains, "test")
|
||||
c.Assert(out, checker.Contains, "-rw")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCpNameHasColon(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /te:s:t")
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "docker-integration")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
dockerCmd(c, "cp", containerID+":/te:s:t", tmpdir)
|
||||
content, err := ioutil.ReadFile(tmpdir + "/te:s:t")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(content), checker.Equals, "lololol\n")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCopyAndRestart(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
expectedMsg := "hello"
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "echo", expectedMsg)
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
// failed to set up container
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0")
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "test-docker-restart-after-copy-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
dockerCmd(c, "cp", fmt.Sprintf("%s:/etc/group", containerID), tmpDir)
|
||||
|
||||
out, _ = dockerCmd(c, "start", "-a", containerID)
|
||||
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, expectedMsg)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCopyCreatedContainer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "create", "--name", "test_cp", "-v", "/test", "busybox")
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
dockerCmd(c, "cp", "test_cp:/bin/sh", tmpDir)
|
||||
}
|
||||
|
||||
// test copy with option `-L`: following symbol link
|
||||
// Check that symlinks to a file behave as expected when copying one from
|
||||
// a container to host following symbol link
|
||||
func (s *DockerSuite) TestCpSymlinkFromConToHostFollowSymlink(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, exitCode := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath+" && ln -s "+cpFullPath+" /dir_link")
|
||||
if exitCode != 0 {
|
||||
c.Fatal("failed to create a container", out)
|
||||
}
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", cleanedContainerID)
|
||||
if strings.TrimSpace(out) != "0" {
|
||||
c.Fatal("failed to set up container", out)
|
||||
}
|
||||
|
||||
testDir, err := ioutil.TempDir("", "test-cp-symlink-container-to-host-follow-symlink")
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(testDir)
|
||||
|
||||
// This copy command should copy the symlink, not the target, into the
|
||||
// temporary directory.
|
||||
dockerCmd(c, "cp", "-L", cleanedContainerID+":"+"/dir_link", testDir)
|
||||
|
||||
expectedPath := filepath.Join(testDir, "dir_link")
|
||||
|
||||
expected := []byte(cpContainerContents)
|
||||
actual, err := ioutil.ReadFile(expectedPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
if !bytes.Equal(actual, expected) {
|
||||
c.Fatalf("Expected copied file to be duplicate of the container symbol link target")
|
||||
}
|
||||
os.Remove(expectedPath)
|
||||
|
||||
// now test copy symbol link to a non-existing file in host
|
||||
expectedPath = filepath.Join(testDir, "somefile_host")
|
||||
// expectedPath shouldn't exist, if exists, remove it
|
||||
if _, err := os.Lstat(expectedPath); err == nil {
|
||||
os.Remove(expectedPath)
|
||||
}
|
||||
|
||||
dockerCmd(c, "cp", "-L", cleanedContainerID+":"+"/dir_link", expectedPath)
|
||||
|
||||
actual, err = ioutil.ReadFile(expectedPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
if !bytes.Equal(actual, expected) {
|
||||
c.Fatalf("Expected copied file to be duplicate of the container symbol link target")
|
||||
}
|
||||
defer os.Remove(expectedPath)
|
||||
}
|
495
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_cp_to_container_test.go
generated
vendored
Normal file
495
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_cp_to_container_test.go
generated
vendored
Normal file
|
@ -0,0 +1,495 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// Try all of the test cases from the archive package which implements the
|
||||
// internals of `docker cp` and ensure that the behavior matches when actually
|
||||
// copying to and from containers.
|
||||
|
||||
// Basic assumptions about SRC and DST:
|
||||
// 1. SRC must exist.
|
||||
// 2. If SRC ends with a trailing separator, it must be a directory.
|
||||
// 3. DST parent directory must exist.
|
||||
// 4. If DST exists as a file, it must not end with a trailing separator.
|
||||
|
||||
// Check that copying from a local path to a symlink in a container copies to
|
||||
// the symlink target and does not overwrite the container symlink itself.
|
||||
func (s *DockerSuite) TestCpToSymlinkDestination(c *check.C) {
|
||||
// stat /tmp/test-cp-to-symlink-destination-262430901/vol3 gets permission denied for the user
|
||||
testRequires(c, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon) // Requires local volume mount bind.
|
||||
|
||||
testVol := getTestDir(c, "test-cp-to-symlink-destination-")
|
||||
defer os.RemoveAll(testVol)
|
||||
|
||||
makeTestContentInDir(c, testVol)
|
||||
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
volumes: defaultVolumes(testVol), // Our bind mount is at /vol2
|
||||
})
|
||||
|
||||
// First, copy a local file to a symlink to a file in the container. This
|
||||
// should overwrite the symlink target contents with the source contents.
|
||||
srcPath := cpPath(testVol, "file2")
|
||||
dstPath := containerCpPath(containerID, "/vol2/symlinkToFile1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// The symlink should not have been modified.
|
||||
c.Assert(symlinkTargetEquals(c, cpPath(testVol, "symlinkToFile1"), "file1"), checker.IsNil)
|
||||
|
||||
// The file should have the contents of "file2" now.
|
||||
c.Assert(fileContentEquals(c, cpPath(testVol, "file1"), "file2\n"), checker.IsNil)
|
||||
|
||||
// Next, copy a local file to a symlink to a directory in the container.
|
||||
// This should copy the file into the symlink target directory.
|
||||
dstPath = containerCpPath(containerID, "/vol2/symlinkToDir1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// The symlink should not have been modified.
|
||||
c.Assert(symlinkTargetEquals(c, cpPath(testVol, "symlinkToDir1"), "dir1"), checker.IsNil)
|
||||
|
||||
// The file should have the contents of "file2" now.
|
||||
c.Assert(fileContentEquals(c, cpPath(testVol, "file2"), "file2\n"), checker.IsNil)
|
||||
|
||||
// Next, copy a file to a symlink to a file that does not exist (a broken
|
||||
// symlink) in the container. This should create the target file with the
|
||||
// contents of the source file.
|
||||
dstPath = containerCpPath(containerID, "/vol2/brokenSymlinkToFileX")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// The symlink should not have been modified.
|
||||
c.Assert(symlinkTargetEquals(c, cpPath(testVol, "brokenSymlinkToFileX"), "fileX"), checker.IsNil)
|
||||
|
||||
// The file should have the contents of "file2" now.
|
||||
c.Assert(fileContentEquals(c, cpPath(testVol, "fileX"), "file2\n"), checker.IsNil)
|
||||
|
||||
// Next, copy a local directory to a symlink to a directory in the
|
||||
// container. This should copy the directory into the symlink target
|
||||
// directory and not modify the symlink.
|
||||
srcPath = cpPath(testVol, "/dir2")
|
||||
dstPath = containerCpPath(containerID, "/vol2/symlinkToDir1")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// The symlink should not have been modified.
|
||||
c.Assert(symlinkTargetEquals(c, cpPath(testVol, "symlinkToDir1"), "dir1"), checker.IsNil)
|
||||
|
||||
// The directory should now contain a copy of "dir2".
|
||||
c.Assert(fileContentEquals(c, cpPath(testVol, "dir1/dir2/file2-1"), "file2-1\n"), checker.IsNil)
|
||||
|
||||
// Next, copy a local directory to a symlink to a local directory that does
|
||||
// not exist (a broken symlink) in the container. This should create the
|
||||
// target as a directory with the contents of the source directory. It
|
||||
// should not modify the symlink.
|
||||
dstPath = containerCpPath(containerID, "/vol2/brokenSymlinkToDirX")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// The symlink should not have been modified.
|
||||
c.Assert(symlinkTargetEquals(c, cpPath(testVol, "brokenSymlinkToDirX"), "dirX"), checker.IsNil)
|
||||
|
||||
// The "dirX" directory should now be a copy of "dir2".
|
||||
c.Assert(fileContentEquals(c, cpPath(testVol, "dirX/file2-1"), "file2-1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// Possibilities are reduced to the remaining 10 cases:
|
||||
//
|
||||
// case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action
|
||||
// ===================================================================================================
|
||||
// A | no | - | no | - | no | create file
|
||||
// B | no | - | no | - | yes | error
|
||||
// C | no | - | yes | no | - | overwrite file
|
||||
// D | no | - | yes | yes | - | create file in dst dir
|
||||
// E | yes | no | no | - | - | create dir, copy contents
|
||||
// F | yes | no | yes | no | - | error
|
||||
// G | yes | no | yes | yes | - | copy dir and contents
|
||||
// H | yes | yes | no | - | - | create dir, copy contents
|
||||
// I | yes | yes | yes | no | - | error
|
||||
// J | yes | yes | yes | yes | - | copy dir contents
|
||||
//
|
||||
|
||||
// A. SRC specifies a file and DST (no trailing path separator) doesn't
|
||||
// exist. This should create a file with the name DST and copy the
|
||||
// contents of the source file into it.
|
||||
func (s *DockerSuite) TestCpToCaseA(c *check.C) {
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
workDir: "/root", command: makeCatFileCommand("itWorks.txt"),
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-case-a")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcPath := cpPath(tmpDir, "file1")
|
||||
dstPath := containerCpPath(containerID, "/root/itWorks.txt")
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// B. SRC specifies a file and DST (with trailing path separator) doesn't
|
||||
// exist. This should cause an error because the copy operation cannot
|
||||
// create a directory when copying a single file.
|
||||
func (s *DockerSuite) TestCpToCaseB(c *check.C) {
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
command: makeCatFileCommand("testDir/file1"),
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-case-b")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcPath := cpPath(tmpDir, "file1")
|
||||
dstDir := containerCpPathTrailingSep(containerID, "testDir")
|
||||
|
||||
err := runDockerCp(c, srcPath, dstDir, nil)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExists error, but got %T: %s", err, err))
|
||||
}
|
||||
|
||||
// C. SRC specifies a file and DST exists as a file. This should overwrite
|
||||
// the file at DST with the contents of the source file.
|
||||
func (s *DockerSuite) TestCpToCaseC(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
command: makeCatFileCommand("file2"),
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-case-c")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcPath := cpPath(tmpDir, "file1")
|
||||
dstPath := containerCpPath(containerID, "/root/file2")
|
||||
|
||||
// Ensure the container's file starts with the original content.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file2\n"), checker.IsNil)
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// D. SRC specifies a file and DST exists as a directory. This should place
|
||||
// a copy of the source file inside it using the basename from SRC. Ensure
|
||||
// this works whether DST has a trailing path separator or not.
|
||||
func (s *DockerSuite) TestCpToCaseD(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true,
|
||||
command: makeCatFileCommand("/dir1/file1"),
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-case-d")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcPath := cpPath(tmpDir, "file1")
|
||||
dstDir := containerCpPath(containerID, "dir1")
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil)
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
// Make new destination container.
|
||||
containerID = makeTestContainer(c, testContainerOptions{
|
||||
addContent: true,
|
||||
command: makeCatFileCommand("/dir1/file1"),
|
||||
})
|
||||
|
||||
dstDir = containerCpPathTrailingSep(containerID, "dir1")
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
|
||||
|
||||
c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// E. SRC specifies a directory and DST does not exist. This should create a
|
||||
// directory at DST and copy the contents of the SRC directory into the DST
|
||||
// directory. Ensure this works whether DST has a trailing path separator or
|
||||
// not.
|
||||
func (s *DockerSuite) TestCpToCaseE(c *check.C) {
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
command: makeCatFileCommand("/testDir/file1-1"),
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-case-e")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcDir := cpPath(tmpDir, "dir1")
|
||||
dstDir := containerCpPath(containerID, "testDir")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1-1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
// Make new destination container.
|
||||
containerID = makeTestContainer(c, testContainerOptions{
|
||||
command: makeCatFileCommand("/testDir/file1-1"),
|
||||
})
|
||||
|
||||
dstDir = containerCpPathTrailingSep(containerID, "testDir")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1-1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// F. SRC specifies a directory and DST exists as a file. This should cause an
|
||||
// error as it is not possible to overwrite a file with a directory.
|
||||
func (s *DockerSuite) TestCpToCaseF(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-case-f")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcDir := cpPath(tmpDir, "dir1")
|
||||
dstFile := containerCpPath(containerID, "/root/file1")
|
||||
|
||||
err := runDockerCp(c, srcDir, dstFile, nil)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
|
||||
}
|
||||
|
||||
// G. SRC specifies a directory and DST exists as a directory. This should copy
|
||||
// the SRC directory and all its contents to the DST directory. Ensure this
|
||||
// works whether DST has a trailing path separator or not.
|
||||
func (s *DockerSuite) TestCpToCaseG(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
command: makeCatFileCommand("dir2/dir1/file1-1"),
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-case-g")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcDir := cpPath(tmpDir, "dir1")
|
||||
dstDir := containerCpPath(containerID, "/root/dir2")
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1-1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
// Make new destination container.
|
||||
containerID = makeTestContainer(c, testContainerOptions{
|
||||
addContent: true,
|
||||
command: makeCatFileCommand("/dir2/dir1/file1-1"),
|
||||
})
|
||||
|
||||
dstDir = containerCpPathTrailingSep(containerID, "/dir2")
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1-1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// H. SRC specifies a directory's contents only and DST does not exist. This
|
||||
// should create a directory at DST and copy the contents of the SRC
|
||||
// directory (but not the directory itself) into the DST directory. Ensure
|
||||
// this works whether DST has a trailing path separator or not.
|
||||
func (s *DockerSuite) TestCpToCaseH(c *check.C) {
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
command: makeCatFileCommand("/testDir/file1-1"),
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-case-h")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcDir := cpPathTrailingSep(tmpDir, "dir1") + "."
|
||||
dstDir := containerCpPath(containerID, "testDir")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1-1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
// Make new destination container.
|
||||
containerID = makeTestContainer(c, testContainerOptions{
|
||||
command: makeCatFileCommand("/testDir/file1-1"),
|
||||
})
|
||||
|
||||
dstDir = containerCpPathTrailingSep(containerID, "testDir")
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1-1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// I. SRC specifies a directory's contents only and DST exists as a file. This
|
||||
// should cause an error as it is not possible to overwrite a file with a
|
||||
// directory.
|
||||
func (s *DockerSuite) TestCpToCaseI(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-case-i")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcDir := cpPathTrailingSep(tmpDir, "dir1") + "."
|
||||
dstFile := containerCpPath(containerID, "/root/file1")
|
||||
|
||||
err := runDockerCp(c, srcDir, dstFile, nil)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
|
||||
}
|
||||
|
||||
// J. SRC specifies a directory's contents only and DST exists as a directory.
|
||||
// This should copy the contents of the SRC directory (but not the directory
|
||||
// itself) into the DST directory. Ensure this works whether DST has a
|
||||
// trailing path separator or not.
|
||||
func (s *DockerSuite) TestCpToCaseJ(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
addContent: true, workDir: "/root",
|
||||
command: makeCatFileCommand("/dir2/file1-1"),
|
||||
})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-case-j")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcDir := cpPathTrailingSep(tmpDir, "dir1") + "."
|
||||
dstDir := containerCpPath(containerID, "/dir2")
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1-1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
// Make new destination container.
|
||||
containerID = makeTestContainer(c, testContainerOptions{
|
||||
command: makeCatFileCommand("/dir2/file1-1"),
|
||||
})
|
||||
|
||||
dstDir = containerCpPathTrailingSep(containerID, "/dir2")
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
|
||||
|
||||
c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
|
||||
|
||||
// Should now contain file1-1's contents.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil)
|
||||
}
|
||||
|
||||
// The `docker cp` command should also ensure that you cannot
|
||||
// write to a container rootfs that is marked as read-only.
|
||||
func (s *DockerSuite) TestCpToErrReadOnlyRootfs(c *check.C) {
|
||||
// --read-only + userns has remount issues
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
tmpDir := getTestDir(c, "test-cp-to-err-read-only-rootfs")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
readOnly: true, workDir: "/root",
|
||||
command: makeCatFileCommand("shouldNotExist"),
|
||||
})
|
||||
|
||||
srcPath := cpPath(tmpDir, "file1")
|
||||
dstPath := containerCpPath(containerID, "/root/shouldNotExist")
|
||||
|
||||
err := runDockerCp(c, srcPath, dstPath, nil)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
c.Assert(isCpCannotCopyReadOnly(err), checker.True, check.Commentf("expected ErrContainerRootfsReadonly error, but got %T: %s", err, err))
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
|
||||
}
|
||||
|
||||
// The `docker cp` command should also ensure that you
|
||||
// cannot write to a volume that is mounted as read-only.
|
||||
func (s *DockerSuite) TestCpToErrReadOnlyVolume(c *check.C) {
|
||||
// --read-only + userns has remount issues
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
tmpDir := getTestDir(c, "test-cp-to-err-read-only-volume")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
containerID := makeTestContainer(c, testContainerOptions{
|
||||
volumes: defaultVolumes(tmpDir), workDir: "/root",
|
||||
command: makeCatFileCommand("/vol_ro/shouldNotExist"),
|
||||
})
|
||||
|
||||
srcPath := cpPath(tmpDir, "file1")
|
||||
dstPath := containerCpPath(containerID, "/vol_ro/shouldNotExist")
|
||||
|
||||
err := runDockerCp(c, srcPath, dstPath, nil)
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
c.Assert(isCpCannotCopyReadOnly(err), checker.True, check.Commentf("expected ErrVolumeReadonly error, but got %T: %s", err, err))
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil)
|
||||
}
|
81
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_cp_to_container_unix_test.go
generated
vendored
Normal file
81
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_cp_to_container_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestCpToContainerWithPermissions(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-host-with-permissions")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
containerName := "permtest"
|
||||
|
||||
_, exc := dockerCmd(c, "create", "--name", containerName, "debian:jessie", "/bin/bash", "-c", "stat -c '%u %g %a' /permdirtest /permdirtest/permtest")
|
||||
c.Assert(exc, checker.Equals, 0)
|
||||
defer dockerCmd(c, "rm", "-f", containerName)
|
||||
|
||||
srcPath := cpPath(tmpDir, "permdirtest")
|
||||
dstPath := containerCpPath(containerName, "/")
|
||||
c.Assert(runDockerCp(c, srcPath, dstPath, []string{"-a"}), checker.IsNil)
|
||||
|
||||
out, err := startContainerGetOutput(c, containerName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("output: %v", out))
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "2 2 700\n65534 65534 400", check.Commentf("output: %v", out))
|
||||
}
|
||||
|
||||
// Check ownership is root, both in non-userns and userns enabled modes
|
||||
func (s *DockerSuite) TestCpCheckDestOwnership(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
tmpVolDir := getTestDir(c, "test-cp-tmpvol")
|
||||
containerID := makeTestContainer(c,
|
||||
testContainerOptions{volumes: []string{fmt.Sprintf("%s:/tmpvol", tmpVolDir)}})
|
||||
|
||||
tmpDir := getTestDir(c, "test-cp-to-check-ownership")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
makeTestContentInDir(c, tmpDir)
|
||||
|
||||
srcPath := cpPath(tmpDir, "file1")
|
||||
dstPath := containerCpPath(containerID, "/tmpvol", "file1")
|
||||
|
||||
err := runDockerCp(c, srcPath, dstPath, nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
stat, err := system.Stat(filepath.Join(tmpVolDir, "file1"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
uid, gid, err := getRootUIDGID()
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(stat.UID(), checker.Equals, uint32(uid), check.Commentf("Copied file not owned by container root UID"))
|
||||
c.Assert(stat.GID(), checker.Equals, uint32(gid), check.Commentf("Copied file not owned by container root GID"))
|
||||
}
|
||||
|
||||
func getRootUIDGID() (int, int, error) {
|
||||
uidgid := strings.Split(filepath.Base(testEnv.DaemonInfo.DockerRootDir), ".")
|
||||
if len(uidgid) == 1 {
|
||||
//user namespace remapping is not turned on; return 0
|
||||
return 0, 0, nil
|
||||
}
|
||||
uid, err := strconv.Atoi(uidgid[0])
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
gid, err := strconv.Atoi(uidgid[1])
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
return uid, gid, nil
|
||||
}
|
305
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_cp_utils_test.go
generated
vendored
Normal file
305
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_cp_utils_test.go
generated
vendored
Normal file
|
@ -0,0 +1,305 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
type fileType uint32
|
||||
|
||||
const (
|
||||
ftRegular fileType = iota
|
||||
ftDir
|
||||
ftSymlink
|
||||
)
|
||||
|
||||
type fileData struct {
|
||||
filetype fileType
|
||||
path string
|
||||
contents string
|
||||
uid int
|
||||
gid int
|
||||
mode int
|
||||
}
|
||||
|
||||
func (fd fileData) creationCommand() string {
|
||||
var command string
|
||||
|
||||
switch fd.filetype {
|
||||
case ftRegular:
|
||||
// Don't overwrite the file if it already exists!
|
||||
command = fmt.Sprintf("if [ ! -f %s ]; then echo %q > %s; fi", fd.path, fd.contents, fd.path)
|
||||
case ftDir:
|
||||
command = fmt.Sprintf("mkdir -p %s", fd.path)
|
||||
case ftSymlink:
|
||||
command = fmt.Sprintf("ln -fs %s %s", fd.contents, fd.path)
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
func mkFilesCommand(fds []fileData) string {
|
||||
commands := make([]string, len(fds))
|
||||
|
||||
for i, fd := range fds {
|
||||
commands[i] = fd.creationCommand()
|
||||
}
|
||||
|
||||
return strings.Join(commands, " && ")
|
||||
}
|
||||
|
||||
var defaultFileData = []fileData{
|
||||
{ftRegular, "file1", "file1", 0, 0, 0666},
|
||||
{ftRegular, "file2", "file2", 0, 0, 0666},
|
||||
{ftRegular, "file3", "file3", 0, 0, 0666},
|
||||
{ftRegular, "file4", "file4", 0, 0, 0666},
|
||||
{ftRegular, "file5", "file5", 0, 0, 0666},
|
||||
{ftRegular, "file6", "file6", 0, 0, 0666},
|
||||
{ftRegular, "file7", "file7", 0, 0, 0666},
|
||||
{ftDir, "dir1", "", 0, 0, 0777},
|
||||
{ftRegular, "dir1/file1-1", "file1-1", 0, 0, 0666},
|
||||
{ftRegular, "dir1/file1-2", "file1-2", 0, 0, 0666},
|
||||
{ftDir, "dir2", "", 0, 0, 0666},
|
||||
{ftRegular, "dir2/file2-1", "file2-1", 0, 0, 0666},
|
||||
{ftRegular, "dir2/file2-2", "file2-2", 0, 0, 0666},
|
||||
{ftDir, "dir3", "", 0, 0, 0666},
|
||||
{ftRegular, "dir3/file3-1", "file3-1", 0, 0, 0666},
|
||||
{ftRegular, "dir3/file3-2", "file3-2", 0, 0, 0666},
|
||||
{ftDir, "dir4", "", 0, 0, 0666},
|
||||
{ftRegular, "dir4/file3-1", "file4-1", 0, 0, 0666},
|
||||
{ftRegular, "dir4/file3-2", "file4-2", 0, 0, 0666},
|
||||
{ftDir, "dir5", "", 0, 0, 0666},
|
||||
{ftSymlink, "symlinkToFile1", "file1", 0, 0, 0666},
|
||||
{ftSymlink, "symlinkToDir1", "dir1", 0, 0, 0666},
|
||||
{ftSymlink, "brokenSymlinkToFileX", "fileX", 0, 0, 0666},
|
||||
{ftSymlink, "brokenSymlinkToDirX", "dirX", 0, 0, 0666},
|
||||
{ftSymlink, "symlinkToAbsDir", "/root", 0, 0, 0666},
|
||||
{ftDir, "permdirtest", "", 2, 2, 0700},
|
||||
{ftRegular, "permdirtest/permtest", "perm_test", 65534, 65534, 0400},
|
||||
}
|
||||
|
||||
func defaultMkContentCommand() string {
|
||||
return mkFilesCommand(defaultFileData)
|
||||
}
|
||||
|
||||
func makeTestContentInDir(c *check.C, dir string) {
|
||||
for _, fd := range defaultFileData {
|
||||
path := filepath.Join(dir, filepath.FromSlash(fd.path))
|
||||
switch fd.filetype {
|
||||
case ftRegular:
|
||||
c.Assert(ioutil.WriteFile(path, []byte(fd.contents+"\n"), os.FileMode(fd.mode)), checker.IsNil)
|
||||
case ftDir:
|
||||
c.Assert(os.Mkdir(path, os.FileMode(fd.mode)), checker.IsNil)
|
||||
case ftSymlink:
|
||||
c.Assert(os.Symlink(fd.contents, path), checker.IsNil)
|
||||
}
|
||||
|
||||
if fd.filetype != ftSymlink && runtime.GOOS != "windows" {
|
||||
c.Assert(os.Chown(path, fd.uid, fd.gid), checker.IsNil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type testContainerOptions struct {
|
||||
addContent bool
|
||||
readOnly bool
|
||||
volumes []string
|
||||
workDir string
|
||||
command string
|
||||
}
|
||||
|
||||
func makeTestContainer(c *check.C, options testContainerOptions) (containerID string) {
|
||||
if options.addContent {
|
||||
mkContentCmd := defaultMkContentCommand()
|
||||
if options.command == "" {
|
||||
options.command = mkContentCmd
|
||||
} else {
|
||||
options.command = fmt.Sprintf("%s && %s", defaultMkContentCommand(), options.command)
|
||||
}
|
||||
}
|
||||
|
||||
if options.command == "" {
|
||||
options.command = "#(nop)"
|
||||
}
|
||||
|
||||
args := []string{"run", "-d"}
|
||||
|
||||
for _, volume := range options.volumes {
|
||||
args = append(args, "-v", volume)
|
||||
}
|
||||
|
||||
if options.workDir != "" {
|
||||
args = append(args, "-w", options.workDir)
|
||||
}
|
||||
|
||||
if options.readOnly {
|
||||
args = append(args, "--read-only")
|
||||
}
|
||||
|
||||
args = append(args, "busybox", "/bin/sh", "-c", options.command)
|
||||
|
||||
out, _ := dockerCmd(c, args...)
|
||||
|
||||
containerID = strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
|
||||
exitCode := strings.TrimSpace(out)
|
||||
if exitCode != "0" {
|
||||
out, _ = dockerCmd(c, "logs", containerID)
|
||||
}
|
||||
c.Assert(exitCode, checker.Equals, "0", check.Commentf("failed to make test container: %s", out))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func makeCatFileCommand(path string) string {
|
||||
return fmt.Sprintf("if [ -f %s ]; then cat %s; fi", path, path)
|
||||
}
|
||||
|
||||
func cpPath(pathElements ...string) string {
|
||||
localizedPathElements := make([]string, len(pathElements))
|
||||
for i, path := range pathElements {
|
||||
localizedPathElements[i] = filepath.FromSlash(path)
|
||||
}
|
||||
return strings.Join(localizedPathElements, string(filepath.Separator))
|
||||
}
|
||||
|
||||
func cpPathTrailingSep(pathElements ...string) string {
|
||||
return fmt.Sprintf("%s%c", cpPath(pathElements...), filepath.Separator)
|
||||
}
|
||||
|
||||
func containerCpPath(containerID string, pathElements ...string) string {
|
||||
joined := strings.Join(pathElements, "/")
|
||||
return fmt.Sprintf("%s:%s", containerID, joined)
|
||||
}
|
||||
|
||||
func containerCpPathTrailingSep(containerID string, pathElements ...string) string {
|
||||
return fmt.Sprintf("%s/", containerCpPath(containerID, pathElements...))
|
||||
}
|
||||
|
||||
func runDockerCp(c *check.C, src, dst string, params []string) (err error) {
|
||||
c.Logf("running `docker cp %s %s %s`", strings.Join(params, " "), src, dst)
|
||||
|
||||
args := []string{"cp"}
|
||||
|
||||
args = append(args, params...)
|
||||
|
||||
args = append(args, src, dst)
|
||||
|
||||
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, args...))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error executing `docker cp` command: %s: %s", err, out)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func startContainerGetOutput(c *check.C, containerID string) (out string, err error) {
|
||||
c.Logf("running `docker start -a %s`", containerID)
|
||||
|
||||
args := []string{"start", "-a", containerID}
|
||||
|
||||
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, args...))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error executing `docker start` command: %s: %s", err, out)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getTestDir(c *check.C, label string) (tmpDir string) {
|
||||
var err error
|
||||
|
||||
tmpDir, err = ioutil.TempDir("", label)
|
||||
// unable to make temporary directory
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func isCpDirNotExist(err error) bool {
|
||||
return strings.Contains(err.Error(), archive.ErrDirNotExists.Error())
|
||||
}
|
||||
|
||||
func isCpCannotCopyDir(err error) bool {
|
||||
return strings.Contains(err.Error(), archive.ErrCannotCopyDir.Error())
|
||||
}
|
||||
|
||||
func isCpCannotCopyReadOnly(err error) bool {
|
||||
return strings.Contains(err.Error(), "marked read-only")
|
||||
}
|
||||
|
||||
func fileContentEquals(c *check.C, filename, contents string) (err error) {
|
||||
c.Logf("checking that file %q contains %q\n", filename, contents)
|
||||
|
||||
fileBytes, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
expectedBytes, err := ioutil.ReadAll(strings.NewReader(contents))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(fileBytes, expectedBytes) {
|
||||
err = fmt.Errorf("file content not equal - expected %q, got %q", string(expectedBytes), string(fileBytes))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func symlinkTargetEquals(c *check.C, symlink, expectedTarget string) (err error) {
|
||||
c.Logf("checking that the symlink %q points to %q\n", symlink, expectedTarget)
|
||||
|
||||
actualTarget, err := os.Readlink(symlink)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if actualTarget != expectedTarget {
|
||||
err = fmt.Errorf("symlink target points to %q not %q", actualTarget, expectedTarget)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func containerStartOutputEquals(c *check.C, containerID, contents string) (err error) {
|
||||
c.Logf("checking that container %q start output contains %q\n", containerID, contents)
|
||||
|
||||
out, err := startContainerGetOutput(c, containerID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if out != contents {
|
||||
err = fmt.Errorf("output contents not equal - expected %q, got %q", contents, out)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func defaultVolumes(tmpDir string) []string {
|
||||
if SameHostDaemon() {
|
||||
return []string{
|
||||
"/vol1",
|
||||
fmt.Sprintf("%s:/vol2", tmpDir),
|
||||
fmt.Sprintf("%s:/vol3", filepath.Join(tmpDir, "vol3")),
|
||||
fmt.Sprintf("%s:/vol_ro:ro", filepath.Join(tmpDir, "vol_ro")),
|
||||
}
|
||||
}
|
||||
|
||||
// Can't bind-mount volumes with separate host daemon.
|
||||
return []string{"/vol1", "/vol2", "/vol3", "/vol_ro:/vol_ro:ro"}
|
||||
}
|
374
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_create_test.go
generated
vendored
Normal file
374
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_create_test.go
generated
vendored
Normal file
|
@ -0,0 +1,374 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/internal/test/fakecontext"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// Make sure we can create a simple container with some args
|
||||
func (s *DockerSuite) TestCreateArgs(c *check.C) {
|
||||
// Intentionally clear entrypoint, as the Windows busybox image needs an entrypoint, which breaks this test
|
||||
out, _ := dockerCmd(c, "create", "--entrypoint=", "busybox", "command", "arg1", "arg2", "arg with space", "-c", "flags")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "inspect", cleanedContainerID)
|
||||
|
||||
var containers []struct {
|
||||
ID string
|
||||
Created time.Time
|
||||
Path string
|
||||
Args []string
|
||||
Image string
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(out), &containers)
|
||||
c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
|
||||
c.Assert(containers, checker.HasLen, 1)
|
||||
|
||||
cont := containers[0]
|
||||
c.Assert(string(cont.Path), checker.Equals, "command", check.Commentf("Unexpected container path. Expected command, received: %s", cont.Path))
|
||||
|
||||
b := false
|
||||
expected := []string{"arg1", "arg2", "arg with space", "-c", "flags"}
|
||||
for i, arg := range expected {
|
||||
if arg != cont.Args[i] {
|
||||
b = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(cont.Args) != len(expected) || b {
|
||||
c.Fatalf("Unexpected args. Expected %v, received: %v", expected, cont.Args)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure we can grow the container's rootfs at creation time.
|
||||
func (s *DockerSuite) TestCreateGrowRootfs(c *check.C) {
|
||||
// Windows and Devicemapper support growing the rootfs
|
||||
if testEnv.OSType != "windows" {
|
||||
testRequires(c, Devicemapper)
|
||||
}
|
||||
out, _ := dockerCmd(c, "create", "--storage-opt", "size=120G", "busybox")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
inspectOut := inspectField(c, cleanedContainerID, "HostConfig.StorageOpt")
|
||||
c.Assert(inspectOut, checker.Equals, "map[size:120G]")
|
||||
}
|
||||
|
||||
// Make sure we cannot shrink the container's rootfs at creation time.
|
||||
func (s *DockerSuite) TestCreateShrinkRootfs(c *check.C) {
|
||||
testRequires(c, Devicemapper)
|
||||
|
||||
// Ensure this fails because of the defaultBaseFsSize is 10G
|
||||
out, _, err := dockerCmdWithError("create", "--storage-opt", "size=5G", "busybox")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "Container size cannot be smaller than")
|
||||
}
|
||||
|
||||
// Make sure we can set hostconfig options too
|
||||
func (s *DockerSuite) TestCreateHostConfig(c *check.C) {
|
||||
out, _ := dockerCmd(c, "create", "-P", "busybox", "echo")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "inspect", cleanedContainerID)
|
||||
|
||||
var containers []struct {
|
||||
HostConfig *struct {
|
||||
PublishAllPorts bool
|
||||
}
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(out), &containers)
|
||||
c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
|
||||
c.Assert(containers, checker.HasLen, 1)
|
||||
|
||||
cont := containers[0]
|
||||
c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none"))
|
||||
c.Assert(cont.HostConfig.PublishAllPorts, check.NotNil, check.Commentf("Expected PublishAllPorts, got false"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateWithPortRange(c *check.C) {
|
||||
out, _ := dockerCmd(c, "create", "-p", "3300-3303:3300-3303/tcp", "busybox", "echo")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "inspect", cleanedContainerID)
|
||||
|
||||
var containers []struct {
|
||||
HostConfig *struct {
|
||||
PortBindings map[nat.Port][]nat.PortBinding
|
||||
}
|
||||
}
|
||||
err := json.Unmarshal([]byte(out), &containers)
|
||||
c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
|
||||
c.Assert(containers, checker.HasLen, 1)
|
||||
|
||||
cont := containers[0]
|
||||
|
||||
c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none"))
|
||||
c.Assert(cont.HostConfig.PortBindings, checker.HasLen, 4, check.Commentf("Expected 4 ports bindings, got %d", len(cont.HostConfig.PortBindings)))
|
||||
|
||||
for k, v := range cont.HostConfig.PortBindings {
|
||||
c.Assert(v, checker.HasLen, 1, check.Commentf("Expected 1 ports binding, for the port %s but found %s", k, v))
|
||||
c.Assert(k.Port(), checker.Equals, v[0].HostPort, check.Commentf("Expected host port %s to match published port %s", k.Port(), v[0].HostPort))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateWithLargePortRange(c *check.C) {
|
||||
out, _ := dockerCmd(c, "create", "-p", "1-65535:1-65535/tcp", "busybox", "echo")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "inspect", cleanedContainerID)
|
||||
|
||||
var containers []struct {
|
||||
HostConfig *struct {
|
||||
PortBindings map[nat.Port][]nat.PortBinding
|
||||
}
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(out), &containers)
|
||||
c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
|
||||
c.Assert(containers, checker.HasLen, 1)
|
||||
|
||||
cont := containers[0]
|
||||
c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none"))
|
||||
c.Assert(cont.HostConfig.PortBindings, checker.HasLen, 65535)
|
||||
|
||||
for k, v := range cont.HostConfig.PortBindings {
|
||||
c.Assert(v, checker.HasLen, 1)
|
||||
c.Assert(k.Port(), checker.Equals, v[0].HostPort, check.Commentf("Expected host port %s to match published port %s", k.Port(), v[0].HostPort))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// "test123" should be printed by docker create + start
|
||||
func (s *DockerSuite) TestCreateEchoStdout(c *check.C) {
|
||||
out, _ := dockerCmd(c, "create", "busybox", "echo", "test123")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "start", "-ai", cleanedContainerID)
|
||||
c.Assert(out, checker.Equals, "test123\n", check.Commentf("container should've printed 'test123', got %q", out))
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateVolumesCreated(c *check.C) {
|
||||
testRequires(c, SameHostDaemon)
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
name := "test_create_volume"
|
||||
dockerCmd(c, "create", "--name", name, "-v", prefix+slash+"foo", "busybox")
|
||||
|
||||
dir, err := inspectMountSourceField(name, prefix+slash+"foo")
|
||||
c.Assert(err, check.IsNil, check.Commentf("Error getting volume host path: %q", err))
|
||||
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
c.Fatalf("Volume was not created")
|
||||
}
|
||||
if err != nil {
|
||||
c.Fatalf("Error statting volume host path: %q", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateLabels(c *check.C) {
|
||||
name := "test_create_labels"
|
||||
expected := map[string]string{"k1": "v1", "k2": "v2"}
|
||||
dockerCmd(c, "create", "--name", name, "-l", "k1=v1", "--label", "k2=v2", "busybox")
|
||||
|
||||
actual := make(map[string]string)
|
||||
inspectFieldAndUnmarshall(c, name, "Config.Labels", &actual)
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
c.Fatalf("Expected %s got %s", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateLabelFromImage(c *check.C) {
|
||||
imageName := "testcreatebuildlabel"
|
||||
buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox
|
||||
LABEL k1=v1 k2=v2`))
|
||||
|
||||
name := "test_create_labels_from_image"
|
||||
expected := map[string]string{"k2": "x", "k3": "v3", "k1": "v1"}
|
||||
dockerCmd(c, "create", "--name", name, "-l", "k2=x", "--label", "k3=v3", imageName)
|
||||
|
||||
actual := make(map[string]string)
|
||||
inspectFieldAndUnmarshall(c, name, "Config.Labels", &actual)
|
||||
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
c.Fatalf("Expected %s got %s", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateHostnameWithNumber(c *check.C) {
|
||||
image := "busybox"
|
||||
// Busybox on Windows does not implement hostname command
|
||||
if testEnv.OSType == "windows" {
|
||||
image = testEnv.PlatformDefaults.BaseImage
|
||||
}
|
||||
out, _ := dockerCmd(c, "run", "-h", "web.0", image, "hostname")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "web.0", check.Commentf("hostname not set, expected `web.0`, got: %s", out))
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateRM(c *check.C) {
|
||||
// Test to make sure we can 'rm' a new container that is in
|
||||
// "Created" state, and has ever been run. Test "rm -f" too.
|
||||
|
||||
// create a container
|
||||
out, _ := dockerCmd(c, "create", "busybox")
|
||||
cID := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "rm", cID)
|
||||
|
||||
// Now do it again so we can "rm -f" this time
|
||||
out, _ = dockerCmd(c, "create", "busybox")
|
||||
|
||||
cID = strings.TrimSpace(out)
|
||||
dockerCmd(c, "rm", "-f", cID)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateModeIpcContainer(c *check.C) {
|
||||
// Uses Linux specific functionality (--ipc)
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
|
||||
out, _ := dockerCmd(c, "create", "busybox")
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "create", fmt.Sprintf("--ipc=container:%s", id), "busybox")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateByImageID(c *check.C) {
|
||||
imageName := "testcreatebyimageid"
|
||||
buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox
|
||||
MAINTAINER dockerio`))
|
||||
imageID := getIDByName(c, imageName)
|
||||
truncatedImageID := stringid.TruncateID(imageID)
|
||||
|
||||
dockerCmd(c, "create", imageID)
|
||||
dockerCmd(c, "create", truncatedImageID)
|
||||
|
||||
// Ensure this fails
|
||||
out, exit, _ := dockerCmdWithError("create", fmt.Sprintf("%s:%s", imageName, imageID))
|
||||
if exit == 0 {
|
||||
c.Fatalf("expected non-zero exit code; received %d", exit)
|
||||
}
|
||||
|
||||
if expected := "invalid reference format"; !strings.Contains(out, expected) {
|
||||
c.Fatalf(`Expected %q in output; got: %s`, expected, out)
|
||||
}
|
||||
|
||||
if i := strings.IndexRune(imageID, ':'); i >= 0 {
|
||||
imageID = imageID[i+1:]
|
||||
}
|
||||
out, exit, _ = dockerCmdWithError("create", fmt.Sprintf("%s:%s", "wrongimage", imageID))
|
||||
if exit == 0 {
|
||||
c.Fatalf("expected non-zero exit code; received %d", exit)
|
||||
}
|
||||
|
||||
if expected := "Unable to find image"; !strings.Contains(out, expected) {
|
||||
c.Fatalf(`Expected %q in output; got: %s`, expected, out)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateStopSignal(c *check.C) {
|
||||
name := "test_create_stop_signal"
|
||||
dockerCmd(c, "create", "--name", name, "--stop-signal", "9", "busybox")
|
||||
|
||||
res := inspectFieldJSON(c, name, "Config.StopSignal")
|
||||
c.Assert(res, checker.Contains, "9")
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateWithWorkdir(c *check.C) {
|
||||
name := "foo"
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
dir := prefix + slash + "home" + slash + "foo" + slash + "bar"
|
||||
|
||||
dockerCmd(c, "create", "--name", name, "-w", dir, "busybox")
|
||||
// Windows does not create the workdir until the container is started
|
||||
if testEnv.OSType == "windows" {
|
||||
dockerCmd(c, "start", name)
|
||||
}
|
||||
dockerCmd(c, "cp", fmt.Sprintf("%s:%s", name, dir), prefix+slash+"tmp")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestCreateWithInvalidLogOpts(c *check.C) {
|
||||
name := "test-invalidate-log-opts"
|
||||
out, _, err := dockerCmdWithError("create", "--name", name, "--log-opt", "invalid=true", "busybox")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "unknown log opt")
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-a")
|
||||
c.Assert(out, checker.Not(checker.Contains), name)
|
||||
}
|
||||
|
||||
// #20972
|
||||
func (s *DockerSuite) TestCreate64ByteHexID(c *check.C) {
|
||||
out := inspectField(c, "busybox", "Id")
|
||||
imageID := strings.TrimPrefix(strings.TrimSpace(string(out)), "sha256:")
|
||||
|
||||
dockerCmd(c, "create", imageID)
|
||||
}
|
||||
|
||||
// Test case for #23498
|
||||
func (s *DockerSuite) TestCreateUnsetEntrypoint(c *check.C) {
|
||||
name := "test-entrypoint"
|
||||
dockerfile := `FROM busybox
|
||||
ADD entrypoint.sh /entrypoint.sh
|
||||
RUN chmod 755 /entrypoint.sh
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD echo foobar`
|
||||
|
||||
ctx := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
fakecontext.WithFiles(map[string]string{
|
||||
"entrypoint.sh": `#!/bin/sh
|
||||
echo "I am an entrypoint"
|
||||
exec "$@"`,
|
||||
}))
|
||||
defer ctx.Close()
|
||||
|
||||
cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
|
||||
|
||||
out := cli.DockerCmd(c, "create", "--entrypoint=", name, "echo", "foo").Combined()
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(id, check.Not(check.Equals), "")
|
||||
out = cli.DockerCmd(c, "start", "-a", id).Combined()
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, "foo")
|
||||
}
|
||||
|
||||
// #22471
|
||||
func (s *DockerSuite) TestCreateStopTimeout(c *check.C) {
|
||||
name1 := "test_create_stop_timeout_1"
|
||||
dockerCmd(c, "create", "--name", name1, "--stop-timeout", "15", "busybox")
|
||||
|
||||
res := inspectFieldJSON(c, name1, "Config.StopTimeout")
|
||||
c.Assert(res, checker.Contains, "15")
|
||||
|
||||
name2 := "test_create_stop_timeout_2"
|
||||
dockerCmd(c, "create", "--name", name2, "busybox")
|
||||
|
||||
res = inspectFieldJSON(c, name2, "Config.StopTimeout")
|
||||
c.Assert(res, checker.Contains, "null")
|
||||
}
|
328
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_daemon_plugins_test.go
generated
vendored
Normal file
328
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_daemon_plugins_test.go
generated
vendored
Normal file
|
@ -0,0 +1,328 @@
|
|||
// +build linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/go-check/check"
|
||||
"golang.org/x/sys/unix"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// TestDaemonRestartWithPluginEnabled tests state restore for an enabled plugin
|
||||
func (s *DockerDaemonSuite) TestDaemonRestartWithPluginEnabled(c *check.C) {
|
||||
testRequires(c, IsAmd64, Network)
|
||||
|
||||
s.d.Start(c)
|
||||
|
||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
|
||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||
}
|
||||
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||
}
|
||||
}()
|
||||
|
||||
s.d.Restart(c)
|
||||
|
||||
out, err := s.d.Cmd("plugin", "ls")
|
||||
if err != nil {
|
||||
c.Fatalf("Could not list plugins: %v %s", err, out)
|
||||
}
|
||||
c.Assert(out, checker.Contains, pName)
|
||||
c.Assert(out, checker.Contains, "true")
|
||||
}
|
||||
|
||||
// TestDaemonRestartWithPluginDisabled tests state restore for a disabled plugin
|
||||
func (s *DockerDaemonSuite) TestDaemonRestartWithPluginDisabled(c *check.C) {
|
||||
testRequires(c, IsAmd64, Network)
|
||||
|
||||
s.d.Start(c)
|
||||
|
||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName, "--disable"); err != nil {
|
||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||
}
|
||||
}()
|
||||
|
||||
s.d.Restart(c)
|
||||
|
||||
out, err := s.d.Cmd("plugin", "ls")
|
||||
if err != nil {
|
||||
c.Fatalf("Could not list plugins: %v %s", err, out)
|
||||
}
|
||||
c.Assert(out, checker.Contains, pName)
|
||||
c.Assert(out, checker.Contains, "false")
|
||||
}
|
||||
|
||||
// TestDaemonKillLiveRestoreWithPlugins SIGKILLs daemon started with --live-restore.
|
||||
// Plugins should continue to run.
|
||||
func (s *DockerDaemonSuite) TestDaemonKillLiveRestoreWithPlugins(c *check.C) {
|
||||
testRequires(c, IsAmd64, Network)
|
||||
|
||||
s.d.Start(c, "--live-restore")
|
||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
|
||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||
}
|
||||
defer func() {
|
||||
s.d.Restart(c, "--live-restore")
|
||||
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||
}
|
||||
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := s.d.Kill(); err != nil {
|
||||
c.Fatalf("Could not kill daemon: %v", err)
|
||||
}
|
||||
|
||||
icmd.RunCommand("pgrep", "-f", pluginProcessName).Assert(c, icmd.Success)
|
||||
}
|
||||
|
||||
// TestDaemonShutdownLiveRestoreWithPlugins SIGTERMs daemon started with --live-restore.
|
||||
// Plugins should continue to run.
|
||||
func (s *DockerDaemonSuite) TestDaemonShutdownLiveRestoreWithPlugins(c *check.C) {
|
||||
testRequires(c, IsAmd64, Network)
|
||||
|
||||
s.d.Start(c, "--live-restore")
|
||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
|
||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||
}
|
||||
defer func() {
|
||||
s.d.Restart(c, "--live-restore")
|
||||
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||
}
|
||||
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := s.d.Interrupt(); err != nil {
|
||||
c.Fatalf("Could not kill daemon: %v", err)
|
||||
}
|
||||
|
||||
icmd.RunCommand("pgrep", "-f", pluginProcessName).Assert(c, icmd.Success)
|
||||
}
|
||||
|
||||
// TestDaemonShutdownWithPlugins shuts down running plugins.
|
||||
func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
|
||||
testRequires(c, IsAmd64, Network, SameHostDaemon)
|
||||
|
||||
s.d.Start(c)
|
||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
|
||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
s.d.Restart(c)
|
||||
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||
}
|
||||
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := s.d.Interrupt(); err != nil {
|
||||
c.Fatalf("Could not kill daemon: %v", err)
|
||||
}
|
||||
|
||||
for {
|
||||
if err := unix.Kill(s.d.Pid(), 0); err == unix.ESRCH {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
icmd.RunCommand("pgrep", "-f", pluginProcessName).Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Error: "exit status 1",
|
||||
})
|
||||
|
||||
s.d.Start(c)
|
||||
icmd.RunCommand("pgrep", "-f", pluginProcessName).Assert(c, icmd.Success)
|
||||
}
|
||||
|
||||
// TestDaemonKillWithPlugins leaves plugins running.
|
||||
func (s *DockerDaemonSuite) TestDaemonKillWithPlugins(c *check.C) {
|
||||
testRequires(c, IsAmd64, Network, SameHostDaemon)
|
||||
|
||||
s.d.Start(c)
|
||||
if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil {
|
||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
s.d.Restart(c)
|
||||
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||
}
|
||||
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := s.d.Kill(); err != nil {
|
||||
c.Fatalf("Could not kill daemon: %v", err)
|
||||
}
|
||||
|
||||
// assert that plugins are running.
|
||||
icmd.RunCommand("pgrep", "-f", pluginProcessName).Assert(c, icmd.Success)
|
||||
}
|
||||
|
||||
// TestVolumePlugin tests volume creation using a plugin.
|
||||
func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) {
|
||||
testRequires(c, IsAmd64, Network)
|
||||
|
||||
volName := "plugin-volume"
|
||||
destDir := "/tmp/data/"
|
||||
destFile := "foo"
|
||||
|
||||
s.d.Start(c)
|
||||
out, err := s.d.Cmd("plugin", "install", pName, "--grant-all-permissions")
|
||||
if err != nil {
|
||||
c.Fatalf("Could not install plugin: %v %s", err, out)
|
||||
}
|
||||
defer func() {
|
||||
if out, err := s.d.Cmd("plugin", "disable", pName); err != nil {
|
||||
c.Fatalf("Could not disable plugin: %v %s", err, out)
|
||||
}
|
||||
|
||||
if out, err := s.d.Cmd("plugin", "remove", pName); err != nil {
|
||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||
}
|
||||
}()
|
||||
|
||||
out, err = s.d.Cmd("volume", "create", "-d", pName, volName)
|
||||
if err != nil {
|
||||
c.Fatalf("Could not create volume: %v %s", err, out)
|
||||
}
|
||||
defer func() {
|
||||
if out, err := s.d.Cmd("volume", "remove", volName); err != nil {
|
||||
c.Fatalf("Could not remove volume: %v %s", err, out)
|
||||
}
|
||||
}()
|
||||
|
||||
out, err = s.d.Cmd("volume", "ls")
|
||||
if err != nil {
|
||||
c.Fatalf("Could not list volume: %v %s", err, out)
|
||||
}
|
||||
c.Assert(out, checker.Contains, volName)
|
||||
c.Assert(out, checker.Contains, pName)
|
||||
|
||||
out, err = s.d.Cmd("run", "--rm", "-v", volName+":"+destDir, "busybox", "touch", destDir+destFile)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = s.d.Cmd("run", "--rm", "-v", volName+":"+destDir, "busybox", "ls", destDir+destFile)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestPluginVolumeRemoveOnRestart(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, Network, IsAmd64)
|
||||
|
||||
s.d.Start(c, "--live-restore=true")
|
||||
|
||||
out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, pName)
|
||||
|
||||
out, err = s.d.Cmd("volume", "create", "--driver", pName, "test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
s.d.Restart(c, "--live-restore=true")
|
||||
|
||||
out, err = s.d.Cmd("plugin", "disable", pName)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "in use")
|
||||
|
||||
out, err = s.d.Cmd("volume", "rm", "test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = s.d.Cmd("plugin", "disable", pName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = s.d.Cmd("plugin", "rm", pName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func existsMountpointWithPrefix(mountpointPrefix string) (bool, error) {
|
||||
mounts, err := mount.GetMounts(nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, mnt := range mounts {
|
||||
if strings.HasPrefix(mnt.Mountpoint, mountpointPrefix) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestPluginListFilterEnabled(c *check.C) {
|
||||
testRequires(c, IsAmd64, Network)
|
||||
|
||||
s.d.Start(c)
|
||||
|
||||
out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pNameWithTag, "--disable")
|
||||
c.Assert(err, check.IsNil, check.Commentf("%s", out))
|
||||
|
||||
defer func() {
|
||||
if out, err := s.d.Cmd("plugin", "remove", pNameWithTag); err != nil {
|
||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||
}
|
||||
}()
|
||||
|
||||
out, err = s.d.Cmd("plugin", "ls", "--filter", "enabled=true")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Not(checker.Contains), pName)
|
||||
|
||||
out, err = s.d.Cmd("plugin", "ls", "--filter", "enabled=false")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, pName)
|
||||
c.Assert(out, checker.Contains, "false")
|
||||
|
||||
out, err = s.d.Cmd("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, pName)
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestPluginListFilterCapability(c *check.C) {
|
||||
testRequires(c, IsAmd64, Network)
|
||||
|
||||
s.d.Start(c)
|
||||
|
||||
out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pNameWithTag, "--disable")
|
||||
c.Assert(err, check.IsNil, check.Commentf("%s", out))
|
||||
|
||||
defer func() {
|
||||
if out, err := s.d.Cmd("plugin", "remove", pNameWithTag); err != nil {
|
||||
c.Fatalf("Could not remove plugin: %v %s", err, out)
|
||||
}
|
||||
}()
|
||||
|
||||
out, err = s.d.Cmd("plugin", "ls", "--filter", "capability=volumedriver")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, pName)
|
||||
|
||||
out, err = s.d.Cmd("plugin", "ls", "--filter", "capability=authz")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Not(checker.Contains), pName)
|
||||
|
||||
out, err = s.d.Cmd("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, pName)
|
||||
}
|
3103
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_daemon_test.go
generated
vendored
Normal file
3103
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_daemon_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
769
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_events_test.go
generated
vendored
Normal file
769
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_events_test.go
generated
vendored
Normal file
|
@ -0,0 +1,769 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
eventtypes "github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/client"
|
||||
eventstestutils "github.com/docker/docker/daemon/events/testutils"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestEventsTimestampFormats(c *check.C) {
|
||||
name := "events-time-format-test"
|
||||
|
||||
// Start stopwatch, generate an event
|
||||
start := daemonTime(c)
|
||||
time.Sleep(1100 * time.Millisecond) // so that first event occur in different second from since (just for the case)
|
||||
dockerCmd(c, "run", "--rm", "--name", name, "busybox", "true")
|
||||
time.Sleep(1100 * time.Millisecond) // so that until > since
|
||||
end := daemonTime(c)
|
||||
|
||||
// List of available time formats to --since
|
||||
unixTs := func(t time.Time) string { return fmt.Sprintf("%v", t.Unix()) }
|
||||
rfc3339 := func(t time.Time) string { return t.Format(time.RFC3339) }
|
||||
duration := func(t time.Time) string { return time.Since(t).String() }
|
||||
|
||||
// --since=$start must contain only the 'untag' event
|
||||
for _, f := range []func(time.Time) string{unixTs, rfc3339, duration} {
|
||||
since, until := f(start), f(end)
|
||||
out, _ := dockerCmd(c, "events", "--since="+since, "--until="+until)
|
||||
events := strings.Split(out, "\n")
|
||||
events = events[:len(events)-1]
|
||||
|
||||
nEvents := len(events)
|
||||
c.Assert(nEvents, checker.GreaterOrEqualThan, 5) //Missing expected event
|
||||
containerEvents := eventActionsByIDAndType(c, events, name, "container")
|
||||
c.Assert(containerEvents, checker.HasLen, 5, check.Commentf("events: %v", events))
|
||||
|
||||
c.Assert(containerEvents[0], checker.Equals, "create", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[1], checker.Equals, "attach", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[2], checker.Equals, "start", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[3], checker.Equals, "die", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[4], checker.Equals, "destroy", check.Commentf("%s", out))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsUntag(c *check.C) {
|
||||
image := "busybox"
|
||||
dockerCmd(c, "tag", image, "utest:tag1")
|
||||
dockerCmd(c, "tag", image, "utest:tag2")
|
||||
dockerCmd(c, "rmi", "utest:tag1")
|
||||
dockerCmd(c, "rmi", "utest:tag2")
|
||||
|
||||
result := icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "events", "--since=1"},
|
||||
Timeout: time.Millisecond * 2500,
|
||||
})
|
||||
result.Assert(c, icmd.Expected{Timeout: true})
|
||||
|
||||
events := strings.Split(result.Stdout(), "\n")
|
||||
nEvents := len(events)
|
||||
// The last element after the split above will be an empty string, so we
|
||||
// get the two elements before the last, which are the untags we're
|
||||
// looking for.
|
||||
for _, v := range events[nEvents-3 : nEvents-1] {
|
||||
c.Assert(v, checker.Contains, "untag", check.Commentf("event should be untag"))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsContainerEvents(c *check.C) {
|
||||
dockerCmd(c, "run", "--rm", "--name", "container-events-test", "busybox", "true")
|
||||
|
||||
out, _ := dockerCmd(c, "events", "--until", daemonUnixTime(c))
|
||||
events := strings.Split(out, "\n")
|
||||
events = events[:len(events)-1]
|
||||
|
||||
nEvents := len(events)
|
||||
c.Assert(nEvents, checker.GreaterOrEqualThan, 5) //Missing expected event
|
||||
containerEvents := eventActionsByIDAndType(c, events, "container-events-test", "container")
|
||||
c.Assert(containerEvents, checker.HasLen, 5, check.Commentf("events: %v", events))
|
||||
|
||||
c.Assert(containerEvents[0], checker.Equals, "create", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[1], checker.Equals, "attach", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[2], checker.Equals, "start", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[3], checker.Equals, "die", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[4], checker.Equals, "destroy", check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsContainerEventsAttrSort(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
dockerCmd(c, "run", "--rm", "--name", "container-events-test", "busybox", "true")
|
||||
|
||||
out, _ := dockerCmd(c, "events", "--filter", "container=container-events-test", "--since", since, "--until", daemonUnixTime(c))
|
||||
events := strings.Split(out, "\n")
|
||||
|
||||
nEvents := len(events)
|
||||
c.Assert(nEvents, checker.GreaterOrEqualThan, 3) //Missing expected event
|
||||
matchedEvents := 0
|
||||
for _, event := range events {
|
||||
matches := eventstestutils.ScanMap(event)
|
||||
if matches["eventType"] == "container" && matches["action"] == "create" {
|
||||
matchedEvents++
|
||||
c.Assert(out, checker.Contains, "(image=busybox, name=container-events-test)", check.Commentf("Event attributes not sorted"))
|
||||
} else if matches["eventType"] == "container" && matches["action"] == "start" {
|
||||
matchedEvents++
|
||||
c.Assert(out, checker.Contains, "(image=busybox, name=container-events-test)", check.Commentf("Event attributes not sorted"))
|
||||
}
|
||||
}
|
||||
c.Assert(matchedEvents, checker.Equals, 2, check.Commentf("missing events for container container-events-test:\n%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsContainerEventsSinceUnixEpoch(c *check.C) {
|
||||
dockerCmd(c, "run", "--rm", "--name", "since-epoch-test", "busybox", "true")
|
||||
timeBeginning := time.Unix(0, 0).Format(time.RFC3339Nano)
|
||||
timeBeginning = strings.Replace(timeBeginning, "Z", ".000000000Z", -1)
|
||||
out, _ := dockerCmd(c, "events", "--since", timeBeginning, "--until", daemonUnixTime(c))
|
||||
events := strings.Split(out, "\n")
|
||||
events = events[:len(events)-1]
|
||||
|
||||
nEvents := len(events)
|
||||
c.Assert(nEvents, checker.GreaterOrEqualThan, 5) //Missing expected event
|
||||
containerEvents := eventActionsByIDAndType(c, events, "since-epoch-test", "container")
|
||||
c.Assert(containerEvents, checker.HasLen, 5, check.Commentf("events: %v", events))
|
||||
|
||||
c.Assert(containerEvents[0], checker.Equals, "create", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[1], checker.Equals, "attach", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[2], checker.Equals, "start", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[3], checker.Equals, "die", check.Commentf("%s", out))
|
||||
c.Assert(containerEvents[4], checker.Equals, "destroy", check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsImageTag(c *check.C) {
|
||||
time.Sleep(1 * time.Second) // because API has seconds granularity
|
||||
since := daemonUnixTime(c)
|
||||
image := "testimageevents:tag"
|
||||
dockerCmd(c, "tag", "busybox", image)
|
||||
|
||||
out, _ := dockerCmd(c, "events",
|
||||
"--since", since, "--until", daemonUnixTime(c))
|
||||
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(events, checker.HasLen, 1, check.Commentf("was expecting 1 event. out=%s", out))
|
||||
event := strings.TrimSpace(events[0])
|
||||
|
||||
matches := eventstestutils.ScanMap(event)
|
||||
c.Assert(matchEventID(matches, image), checker.True, check.Commentf("matches: %v\nout:\n%s", matches, out))
|
||||
c.Assert(matches["action"], checker.Equals, "tag")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsImagePull(c *check.C) {
|
||||
// TODO Windows: Enable this test once pull and reliable image names are available
|
||||
testRequires(c, DaemonIsLinux)
|
||||
since := daemonUnixTime(c)
|
||||
testRequires(c, Network)
|
||||
|
||||
dockerCmd(c, "pull", "hello-world")
|
||||
|
||||
out, _ := dockerCmd(c, "events",
|
||||
"--since", since, "--until", daemonUnixTime(c))
|
||||
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
event := strings.TrimSpace(events[len(events)-1])
|
||||
matches := eventstestutils.ScanMap(event)
|
||||
c.Assert(matches["id"], checker.Equals, "hello-world:latest")
|
||||
c.Assert(matches["action"], checker.Equals, "pull")
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsImageImport(c *check.C) {
|
||||
// TODO Windows CI. This should be portable once export/import are
|
||||
// more reliable (@swernli)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
since := daemonUnixTime(c)
|
||||
out, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "export", cleanedContainerID),
|
||||
exec.Command(dockerBinary, "import", "-"),
|
||||
)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("import failed with output: %q", out))
|
||||
imageRef := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=import")
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(events, checker.HasLen, 1)
|
||||
matches := eventstestutils.ScanMap(events[0])
|
||||
c.Assert(matches["id"], checker.Equals, imageRef, check.Commentf("matches: %v\nout:\n%s\n", matches, out))
|
||||
c.Assert(matches["action"], checker.Equals, "import", check.Commentf("matches: %v\nout:\n%s\n", matches, out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsImageLoad(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
myImageName := "footest:v1"
|
||||
dockerCmd(c, "tag", "busybox", myImageName)
|
||||
since := daemonUnixTime(c)
|
||||
|
||||
out, _ := dockerCmd(c, "images", "-q", "--no-trunc", myImageName)
|
||||
longImageID := strings.TrimSpace(out)
|
||||
c.Assert(longImageID, checker.Not(check.Equals), "", check.Commentf("Id should not be empty"))
|
||||
|
||||
dockerCmd(c, "save", "-o", "saveimg.tar", myImageName)
|
||||
dockerCmd(c, "rmi", myImageName)
|
||||
out, _ = dockerCmd(c, "images", "-q", myImageName)
|
||||
noImageID := strings.TrimSpace(out)
|
||||
c.Assert(noImageID, checker.Equals, "", check.Commentf("Should not have any image"))
|
||||
dockerCmd(c, "load", "-i", "saveimg.tar")
|
||||
|
||||
result := icmd.RunCommand("rm", "-rf", "saveimg.tar")
|
||||
result.Assert(c, icmd.Success)
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-q", "--no-trunc", myImageName)
|
||||
imageID := strings.TrimSpace(out)
|
||||
c.Assert(imageID, checker.Equals, longImageID, check.Commentf("Should have same image id as before"))
|
||||
|
||||
out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=load")
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(events, checker.HasLen, 1)
|
||||
matches := eventstestutils.ScanMap(events[0])
|
||||
c.Assert(matches["id"], checker.Equals, imageID, check.Commentf("matches: %v\nout:\n%s\n", matches, out))
|
||||
c.Assert(matches["action"], checker.Equals, "load", check.Commentf("matches: %v\nout:\n%s\n", matches, out))
|
||||
|
||||
out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=save")
|
||||
events = strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(events, checker.HasLen, 1)
|
||||
matches = eventstestutils.ScanMap(events[0])
|
||||
c.Assert(matches["id"], checker.Equals, imageID, check.Commentf("matches: %v\nout:\n%s\n", matches, out))
|
||||
c.Assert(matches["action"], checker.Equals, "save", check.Commentf("matches: %v\nout:\n%s\n", matches, out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsPluginOps(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, IsAmd64, Network)
|
||||
|
||||
since := daemonUnixTime(c)
|
||||
|
||||
dockerCmd(c, "plugin", "install", pNameWithTag, "--grant-all-permissions")
|
||||
dockerCmd(c, "plugin", "disable", pNameWithTag)
|
||||
dockerCmd(c, "plugin", "remove", pNameWithTag)
|
||||
|
||||
out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c))
|
||||
events := strings.Split(out, "\n")
|
||||
events = events[:len(events)-1]
|
||||
|
||||
nEvents := len(events)
|
||||
c.Assert(nEvents, checker.GreaterOrEqualThan, 4)
|
||||
|
||||
pluginEvents := eventActionsByIDAndType(c, events, pNameWithTag, "plugin")
|
||||
c.Assert(pluginEvents, checker.HasLen, 4, check.Commentf("events: %v", events))
|
||||
|
||||
c.Assert(pluginEvents[0], checker.Equals, "pull", check.Commentf("%s", out))
|
||||
c.Assert(pluginEvents[1], checker.Equals, "enable", check.Commentf("%s", out))
|
||||
c.Assert(pluginEvents[2], checker.Equals, "disable", check.Commentf("%s", out))
|
||||
c.Assert(pluginEvents[3], checker.Equals, "remove", check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFilters(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
dockerCmd(c, "run", "--rm", "busybox", "true")
|
||||
dockerCmd(c, "run", "--rm", "busybox", "true")
|
||||
out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=die")
|
||||
parseEvents(c, out, "die")
|
||||
|
||||
out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=die", "--filter", "event=start")
|
||||
parseEvents(c, out, "die|start")
|
||||
|
||||
// make sure we at least got 2 start events
|
||||
count := strings.Count(out, "start")
|
||||
c.Assert(strings.Count(out, "start"), checker.GreaterOrEqualThan, 2, check.Commentf("should have had 2 start events but had %d, out: %s", count, out))
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFilterImageName(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--name", "container_1", "-d", "busybox:latest", "true")
|
||||
container1 := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "run", "--name", "container_2", "-d", "busybox", "true")
|
||||
container2 := strings.TrimSpace(out)
|
||||
|
||||
name := "busybox"
|
||||
out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", fmt.Sprintf("image=%s", name))
|
||||
events := strings.Split(out, "\n")
|
||||
events = events[:len(events)-1]
|
||||
c.Assert(events, checker.Not(checker.HasLen), 0) //Expected events but found none for the image busybox:latest
|
||||
count1 := 0
|
||||
count2 := 0
|
||||
|
||||
for _, e := range events {
|
||||
if strings.Contains(e, container1) {
|
||||
count1++
|
||||
} else if strings.Contains(e, container2) {
|
||||
count2++
|
||||
}
|
||||
}
|
||||
c.Assert(count1, checker.Not(checker.Equals), 0, check.Commentf("Expected event from container but got %d from %s", count1, container1))
|
||||
c.Assert(count2, checker.Not(checker.Equals), 0, check.Commentf("Expected event from container but got %d from %s", count2, container2))
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFilterLabels(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
label := "io.docker.testing=foo"
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "-l", label, "busybox:latest", "true")
|
||||
container1 := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
container2 := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(
|
||||
c,
|
||||
"events",
|
||||
"--since", since,
|
||||
"--until", daemonUnixTime(c),
|
||||
"--filter", fmt.Sprintf("label=%s", label))
|
||||
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(events), checker.Equals, 3)
|
||||
|
||||
for _, e := range events {
|
||||
c.Assert(e, checker.Contains, container1)
|
||||
c.Assert(e, checker.Not(checker.Contains), container2)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFilterImageLabels(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
name := "labelfiltertest"
|
||||
label := "io.docker.testing=image"
|
||||
|
||||
// Build a test image.
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`
|
||||
FROM busybox:latest
|
||||
LABEL %s`, label)))
|
||||
dockerCmd(c, "tag", name, "labelfiltertest:tag1")
|
||||
dockerCmd(c, "tag", name, "labelfiltertest:tag2")
|
||||
dockerCmd(c, "tag", "busybox:latest", "labelfiltertest:tag3")
|
||||
|
||||
out, _ := dockerCmd(
|
||||
c,
|
||||
"events",
|
||||
"--since", since,
|
||||
"--until", daemonUnixTime(c),
|
||||
"--filter", fmt.Sprintf("label=%s", label),
|
||||
"--filter", "type=image")
|
||||
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
|
||||
// 2 events from the "docker tag" command, another one is from "docker build"
|
||||
c.Assert(events, checker.HasLen, 3, check.Commentf("Events == %s", events))
|
||||
for _, e := range events {
|
||||
c.Assert(e, checker.Contains, "labelfiltertest")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFilterContainer(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
nameID := make(map[string]string)
|
||||
|
||||
for _, name := range []string{"container_1", "container_2"} {
|
||||
dockerCmd(c, "run", "--name", name, "busybox", "true")
|
||||
id := inspectField(c, name, "Id")
|
||||
nameID[name] = id
|
||||
}
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
|
||||
checkEvents := func(id string, events []string) error {
|
||||
if len(events) != 4 { // create, attach, start, die
|
||||
return fmt.Errorf("expected 4 events, got %v", events)
|
||||
}
|
||||
for _, event := range events {
|
||||
matches := eventstestutils.ScanMap(event)
|
||||
if !matchEventID(matches, id) {
|
||||
return fmt.Errorf("expected event for container id %s: %s - parsed container id: %s", id, event, matches["id"])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for name, ID := range nameID {
|
||||
// filter by names
|
||||
out, _ := dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "container="+name)
|
||||
events := strings.Split(strings.TrimSuffix(out, "\n"), "\n")
|
||||
c.Assert(checkEvents(ID, events), checker.IsNil)
|
||||
|
||||
// filter by ID's
|
||||
out, _ = dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "container="+ID)
|
||||
events = strings.Split(strings.TrimSuffix(out, "\n"), "\n")
|
||||
c.Assert(checkEvents(ID, events), checker.IsNil)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsCommit(c *check.C) {
|
||||
// Problematic on Windows as cannot commit a running container
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out := runSleepingContainer(c)
|
||||
cID := strings.TrimSpace(out)
|
||||
cli.WaitRun(c, cID)
|
||||
|
||||
cli.DockerCmd(c, "commit", "-m", "test", cID)
|
||||
cli.DockerCmd(c, "stop", cID)
|
||||
cli.WaitExited(c, cID, 5*time.Second)
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
out = cli.DockerCmd(c, "events", "-f", "container="+cID, "--until="+until).Combined()
|
||||
c.Assert(out, checker.Contains, "commit", check.Commentf("Missing 'commit' log event"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsCopy(c *check.C) {
|
||||
// Build a test image.
|
||||
buildImageSuccessfully(c, "cpimg", build.WithDockerfile(`
|
||||
FROM busybox
|
||||
RUN echo HI > /file`))
|
||||
id := getIDByName(c, "cpimg")
|
||||
|
||||
// Create an empty test file.
|
||||
tempFile, err := ioutil.TempFile("", "test-events-copy-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.Remove(tempFile.Name())
|
||||
|
||||
c.Assert(tempFile.Close(), checker.IsNil)
|
||||
|
||||
dockerCmd(c, "create", "--name=cptest", id)
|
||||
|
||||
dockerCmd(c, "cp", "cptest:/file", tempFile.Name())
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
out, _ := dockerCmd(c, "events", "--since=0", "-f", "container=cptest", "--until="+until)
|
||||
c.Assert(out, checker.Contains, "archive-path", check.Commentf("Missing 'archive-path' log event\n"))
|
||||
|
||||
dockerCmd(c, "cp", tempFile.Name(), "cptest:/filecopy")
|
||||
|
||||
until = daemonUnixTime(c)
|
||||
out, _ = dockerCmd(c, "events", "-f", "container=cptest", "--until="+until)
|
||||
c.Assert(out, checker.Contains, "extract-to-dir", check.Commentf("Missing 'extract-to-dir' log event"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsResize(c *check.C) {
|
||||
out := runSleepingContainer(c, "-d")
|
||||
cID := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(cID), checker.IsNil)
|
||||
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
options := types.ResizeOptions{
|
||||
Height: 80,
|
||||
Width: 24,
|
||||
}
|
||||
err = cli.ContainerResize(context.Background(), cID, options)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "stop", cID)
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
out, _ = dockerCmd(c, "events", "-f", "container="+cID, "--until="+until)
|
||||
c.Assert(out, checker.Contains, "resize", check.Commentf("Missing 'resize' log event"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsAttach(c *check.C) {
|
||||
// TODO Windows CI: Figure out why this test fails intermittently (TP5).
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out := cli.DockerCmd(c, "run", "-di", "busybox", "cat").Combined()
|
||||
cID := strings.TrimSpace(out)
|
||||
cli.WaitRun(c, cID)
|
||||
|
||||
cmd := exec.Command(dockerBinary, "attach", cID)
|
||||
stdin, err := cmd.StdinPipe()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer stdin.Close()
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer stdout.Close()
|
||||
c.Assert(cmd.Start(), checker.IsNil)
|
||||
defer func() {
|
||||
cmd.Process.Kill()
|
||||
cmd.Wait()
|
||||
}()
|
||||
|
||||
// Make sure we're done attaching by writing/reading some stuff
|
||||
_, err = stdin.Write([]byte("hello\n"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
out, err = bufio.NewReader(stdout).ReadString('\n')
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "hello", check.Commentf("expected 'hello'"))
|
||||
|
||||
c.Assert(stdin.Close(), checker.IsNil)
|
||||
|
||||
cli.DockerCmd(c, "kill", cID)
|
||||
cli.WaitExited(c, cID, 5*time.Second)
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
out = cli.DockerCmd(c, "events", "-f", "container="+cID, "--until="+until).Combined()
|
||||
c.Assert(out, checker.Contains, "attach", check.Commentf("Missing 'attach' log event"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsRename(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "--name", "oldName", "busybox", "true")
|
||||
cID := strings.TrimSpace(out)
|
||||
dockerCmd(c, "rename", "oldName", "newName")
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
// filter by the container id because the name in the event will be the new name.
|
||||
out, _ = dockerCmd(c, "events", "-f", "container="+cID, "--until", until)
|
||||
c.Assert(out, checker.Contains, "rename", check.Commentf("Missing 'rename' log event\n"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsTop(c *check.C) {
|
||||
// Problematic on Windows as Windows does not support top
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out := runSleepingContainer(c, "-d")
|
||||
cID := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(cID), checker.IsNil)
|
||||
|
||||
dockerCmd(c, "top", cID)
|
||||
dockerCmd(c, "stop", cID)
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
out, _ = dockerCmd(c, "events", "-f", "container="+cID, "--until="+until)
|
||||
c.Assert(out, checker.Contains, " top", check.Commentf("Missing 'top' log event"))
|
||||
}
|
||||
|
||||
// #14316
|
||||
func (s *DockerRegistrySuite) TestEventsImageFilterPush(c *check.C) {
|
||||
// Problematic to port for Windows CI during TP5 timeframe until
|
||||
// supporting push
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, Network)
|
||||
repoName := fmt.Sprintf("%v/dockercli/testf", privateRegistryURL)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
cID := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(cID), checker.IsNil)
|
||||
|
||||
dockerCmd(c, "commit", cID, repoName)
|
||||
dockerCmd(c, "stop", cID)
|
||||
dockerCmd(c, "push", repoName)
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
out, _ = dockerCmd(c, "events", "-f", "image="+repoName, "-f", "event=push", "--until", until)
|
||||
c.Assert(out, checker.Contains, repoName, check.Commentf("Missing 'push' log event for %s", repoName))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFilterType(c *check.C) {
|
||||
// FIXME(vdemeester) fails on e2e run
|
||||
testRequires(c, SameHostDaemon)
|
||||
since := daemonUnixTime(c)
|
||||
name := "labelfiltertest"
|
||||
label := "io.docker.testing=image"
|
||||
|
||||
// Build a test image.
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`
|
||||
FROM busybox:latest
|
||||
LABEL %s`, label)))
|
||||
dockerCmd(c, "tag", name, "labelfiltertest:tag1")
|
||||
dockerCmd(c, "tag", name, "labelfiltertest:tag2")
|
||||
dockerCmd(c, "tag", "busybox:latest", "labelfiltertest:tag3")
|
||||
|
||||
out, _ := dockerCmd(
|
||||
c,
|
||||
"events",
|
||||
"--since", since,
|
||||
"--until", daemonUnixTime(c),
|
||||
"--filter", fmt.Sprintf("label=%s", label),
|
||||
"--filter", "type=image")
|
||||
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
|
||||
// 2 events from the "docker tag" command, another one is from "docker build"
|
||||
c.Assert(events, checker.HasLen, 3, check.Commentf("Events == %s", events))
|
||||
for _, e := range events {
|
||||
c.Assert(e, checker.Contains, "labelfiltertest")
|
||||
}
|
||||
|
||||
out, _ = dockerCmd(
|
||||
c,
|
||||
"events",
|
||||
"--since", since,
|
||||
"--until", daemonUnixTime(c),
|
||||
"--filter", fmt.Sprintf("label=%s", label),
|
||||
"--filter", "type=container")
|
||||
events = strings.Split(strings.TrimSpace(out), "\n")
|
||||
|
||||
// Events generated by the container that builds the image
|
||||
c.Assert(events, checker.HasLen, 2, check.Commentf("Events == %s", events))
|
||||
|
||||
out, _ = dockerCmd(
|
||||
c,
|
||||
"events",
|
||||
"--since", since,
|
||||
"--until", daemonUnixTime(c),
|
||||
"--filter", "type=network")
|
||||
events = strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(events), checker.GreaterOrEqualThan, 1, check.Commentf("Events == %s", events))
|
||||
}
|
||||
|
||||
// #25798
|
||||
func (s *DockerSuite) TestEventsSpecialFiltersWithExecCreate(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
runSleepingContainer(c, "--name", "test-container", "-d")
|
||||
waitRun("test-container")
|
||||
|
||||
dockerCmd(c, "exec", "test-container", "echo", "hello-world")
|
||||
|
||||
out, _ := dockerCmd(
|
||||
c,
|
||||
"events",
|
||||
"--since", since,
|
||||
"--until", daemonUnixTime(c),
|
||||
"--filter",
|
||||
"event='exec_create: echo hello-world'",
|
||||
)
|
||||
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(events), checker.Equals, 1, check.Commentf("%s", out))
|
||||
|
||||
out, _ = dockerCmd(
|
||||
c,
|
||||
"events",
|
||||
"--since", since,
|
||||
"--until", daemonUnixTime(c),
|
||||
"--filter",
|
||||
"event=exec_create",
|
||||
)
|
||||
c.Assert(len(events), checker.Equals, 1, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFilterImageInContainerAction(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
dockerCmd(c, "run", "--name", "test-container", "-d", "busybox", "true")
|
||||
waitRun("test-container")
|
||||
|
||||
out, _ := dockerCmd(c, "events", "--filter", "image=busybox", "--since", since, "--until", daemonUnixTime(c))
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(events), checker.GreaterThan, 1, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsContainerRestart(c *check.C) {
|
||||
dockerCmd(c, "run", "-d", "--name=testEvent", "--restart=on-failure:3", "busybox", "false")
|
||||
|
||||
// wait until test2 is auto removed.
|
||||
waitTime := 10 * time.Second
|
||||
if testEnv.OSType == "windows" {
|
||||
// Windows takes longer...
|
||||
waitTime = 90 * time.Second
|
||||
}
|
||||
|
||||
err := waitInspect("testEvent", "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTime)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var (
|
||||
createCount int
|
||||
startCount int
|
||||
dieCount int
|
||||
)
|
||||
out, _ := dockerCmd(c, "events", "--since=0", "--until", daemonUnixTime(c), "-f", "container=testEvent")
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
|
||||
nEvents := len(events)
|
||||
c.Assert(nEvents, checker.GreaterOrEqualThan, 1) //Missing expected event
|
||||
actions := eventActionsByIDAndType(c, events, "testEvent", "container")
|
||||
|
||||
for _, a := range actions {
|
||||
switch a {
|
||||
case "create":
|
||||
createCount++
|
||||
case "start":
|
||||
startCount++
|
||||
case "die":
|
||||
dieCount++
|
||||
}
|
||||
}
|
||||
c.Assert(createCount, checker.Equals, 1, check.Commentf("testEvent should be created 1 times: %v", actions))
|
||||
c.Assert(startCount, checker.Equals, 4, check.Commentf("testEvent should start 4 times: %v", actions))
|
||||
c.Assert(dieCount, checker.Equals, 4, check.Commentf("testEvent should die 4 times: %v", actions))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsSinceInTheFuture(c *check.C) {
|
||||
dockerCmd(c, "run", "--name", "test-container", "-d", "busybox", "true")
|
||||
waitRun("test-container")
|
||||
|
||||
since := daemonTime(c)
|
||||
until := since.Add(time.Duration(-24) * time.Hour)
|
||||
out, _, err := dockerCmdWithError("events", "--filter", "image=busybox", "--since", parseEventTime(since), "--until", parseEventTime(until))
|
||||
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "cannot be after `until`")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsUntilInThePast(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
|
||||
dockerCmd(c, "run", "--name", "test-container", "-d", "busybox", "true")
|
||||
waitRun("test-container")
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
|
||||
dockerCmd(c, "run", "--name", "test-container2", "-d", "busybox", "true")
|
||||
waitRun("test-container2")
|
||||
|
||||
out, _ := dockerCmd(c, "events", "--filter", "image=busybox", "--since", since, "--until", until)
|
||||
|
||||
c.Assert(out, checker.Not(checker.Contains), "test-container2")
|
||||
c.Assert(out, checker.Contains, "test-container")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFormat(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
dockerCmd(c, "run", "--rm", "busybox", "true")
|
||||
dockerCmd(c, "run", "--rm", "busybox", "true")
|
||||
out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--format", "{{json .}}")
|
||||
dec := json.NewDecoder(strings.NewReader(out))
|
||||
// make sure we got 2 start events
|
||||
startCount := 0
|
||||
for {
|
||||
var err error
|
||||
var ev eventtypes.Message
|
||||
if err = dec.Decode(&ev); err == io.EOF {
|
||||
break
|
||||
}
|
||||
c.Assert(err, checker.IsNil)
|
||||
if ev.Status == "start" {
|
||||
startCount++
|
||||
}
|
||||
}
|
||||
|
||||
c.Assert(startCount, checker.Equals, 2, check.Commentf("should have had 2 start events but had %d, out: %s", startCount, out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFormatBadFunc(c *check.C) {
|
||||
// make sure it fails immediately, without receiving any event
|
||||
result := dockerCmdWithResult("events", "--format", "{{badFuncString .}}")
|
||||
result.Assert(c, icmd.Expected{
|
||||
Error: "exit status 64",
|
||||
ExitCode: 64,
|
||||
Err: "Error parsing format: template: :1: function \"badFuncString\" not defined",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFormatBadField(c *check.C) {
|
||||
// make sure it fails immediately, without receiving any event
|
||||
result := dockerCmdWithResult("events", "--format", "{{.badFieldString}}")
|
||||
result.Assert(c, icmd.Expected{
|
||||
Error: "exit status 64",
|
||||
ExitCode: 64,
|
||||
Err: "Error parsing format: template: :1:2: executing \"\" at <.badFieldString>: can't evaluate field badFieldString in type *events.Message",
|
||||
})
|
||||
}
|
511
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_events_unix_test.go
generated
vendored
Normal file
511
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_events_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,511 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
"github.com/kr/pty"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// #5979
|
||||
func (s *DockerSuite) TestEventsRedirectStdout(c *check.C) {
|
||||
since := daemonUnixTime(c)
|
||||
dockerCmd(c, "run", "busybox", "true")
|
||||
|
||||
file, err := ioutil.TempFile("", "")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("could not create temp file"))
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
command := fmt.Sprintf("%s events --since=%s --until=%s > %s", dockerBinary, since, daemonUnixTime(c), file.Name())
|
||||
_, tty, err := pty.Open()
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Could not open pty"))
|
||||
cmd := exec.Command("sh", "-c", command)
|
||||
cmd.Stdin = tty
|
||||
cmd.Stdout = tty
|
||||
cmd.Stderr = tty
|
||||
c.Assert(cmd.Run(), checker.IsNil, check.Commentf("run err for command %q", command))
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
for _, ch := range scanner.Text() {
|
||||
c.Assert(unicode.IsControl(ch), checker.False, check.Commentf("found control character %v", []byte(string(ch))))
|
||||
}
|
||||
}
|
||||
c.Assert(scanner.Err(), checker.IsNil, check.Commentf("Scan err for command %q", command))
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsOOMDisableFalse(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, oomControl, memoryLimitSupport, swapMemorySupport, NotPpc64le)
|
||||
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
defer close(errChan)
|
||||
out, exitCode, _ := dockerCmdWithError("run", "--name", "oomFalse", "-m", "10MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done")
|
||||
if expected := 137; exitCode != expected {
|
||||
errChan <- fmt.Errorf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out)
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case err := <-errChan:
|
||||
c.Assert(err, checker.IsNil)
|
||||
case <-time.After(30 * time.Second):
|
||||
c.Fatal("Timeout waiting for container to die on OOM")
|
||||
}
|
||||
|
||||
out, _ := dockerCmd(c, "events", "--since=0", "-f", "container=oomFalse", "--until", daemonUnixTime(c))
|
||||
events := strings.Split(strings.TrimSuffix(out, "\n"), "\n")
|
||||
nEvents := len(events)
|
||||
|
||||
c.Assert(nEvents, checker.GreaterOrEqualThan, 5) //Missing expected event
|
||||
c.Assert(parseEventAction(c, events[nEvents-5]), checker.Equals, "create")
|
||||
c.Assert(parseEventAction(c, events[nEvents-4]), checker.Equals, "attach")
|
||||
c.Assert(parseEventAction(c, events[nEvents-3]), checker.Equals, "start")
|
||||
c.Assert(parseEventAction(c, events[nEvents-2]), checker.Equals, "oom")
|
||||
c.Assert(parseEventAction(c, events[nEvents-1]), checker.Equals, "die")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsOOMDisableTrue(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, oomControl, memoryLimitSupport, NotArm, swapMemorySupport, NotPpc64le)
|
||||
|
||||
errChan := make(chan error)
|
||||
observer, err := newEventObserver(c)
|
||||
c.Assert(err, checker.IsNil)
|
||||
err = observer.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer observer.Stop()
|
||||
|
||||
go func() {
|
||||
defer close(errChan)
|
||||
out, exitCode, _ := dockerCmdWithError("run", "--oom-kill-disable=true", "--name", "oomTrue", "-m", "10MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done")
|
||||
if expected := 137; exitCode != expected {
|
||||
errChan <- fmt.Errorf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out)
|
||||
}
|
||||
}()
|
||||
|
||||
c.Assert(waitRun("oomTrue"), checker.IsNil)
|
||||
defer dockerCmdWithResult("kill", "oomTrue")
|
||||
containerID := inspectField(c, "oomTrue", "Id")
|
||||
|
||||
testActions := map[string]chan bool{
|
||||
"oom": make(chan bool),
|
||||
}
|
||||
|
||||
matcher := matchEventLine(containerID, "container", testActions)
|
||||
processor := processEventMatch(testActions)
|
||||
go observer.Match(matcher, processor)
|
||||
|
||||
select {
|
||||
case <-time.After(20 * time.Second):
|
||||
observer.CheckEventError(c, containerID, "oom", matcher)
|
||||
case <-testActions["oom"]:
|
||||
// ignore, done
|
||||
case errRun := <-errChan:
|
||||
if errRun != nil {
|
||||
c.Fatalf("%v", errRun)
|
||||
} else {
|
||||
c.Fatalf("container should be still running but it's not")
|
||||
}
|
||||
}
|
||||
|
||||
status := inspectField(c, "oomTrue", "State.Status")
|
||||
c.Assert(strings.TrimSpace(status), checker.Equals, "running", check.Commentf("container should be still running"))
|
||||
}
|
||||
|
||||
// #18453
|
||||
func (s *DockerSuite) TestEventsContainerFilterByName(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
cOut, _ := dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top")
|
||||
c1 := strings.TrimSpace(cOut)
|
||||
waitRun("foo")
|
||||
cOut, _ = dockerCmd(c, "run", "--name=bar", "-d", "busybox", "top")
|
||||
c2 := strings.TrimSpace(cOut)
|
||||
waitRun("bar")
|
||||
out, _ := dockerCmd(c, "events", "-f", "container=foo", "--since=0", "--until", daemonUnixTime(c))
|
||||
c.Assert(out, checker.Contains, c1, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Not(checker.Contains), c2, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
// #18453
|
||||
func (s *DockerSuite) TestEventsContainerFilterBeforeCreate(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
buf := &bytes.Buffer{}
|
||||
cmd := exec.Command(dockerBinary, "events", "-f", "container=foo", "--since=0")
|
||||
cmd.Stdout = buf
|
||||
c.Assert(cmd.Start(), check.IsNil)
|
||||
defer cmd.Wait()
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
// Sleep for a second to make sure we are testing the case where events are listened before container starts.
|
||||
time.Sleep(time.Second)
|
||||
id, _ := dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top")
|
||||
cID := strings.TrimSpace(id)
|
||||
for i := 0; ; i++ {
|
||||
out := buf.String()
|
||||
if strings.Contains(out, cID) {
|
||||
break
|
||||
}
|
||||
if i > 30 {
|
||||
c.Fatalf("Missing event of container (foo, %v), got %q", cID, out)
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeEvents(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
since := daemonUnixTime(c)
|
||||
|
||||
// Observe create/mount volume actions
|
||||
dockerCmd(c, "volume", "create", "test-event-volume-local")
|
||||
dockerCmd(c, "run", "--name", "test-volume-container", "--volume", "test-event-volume-local:/foo", "-d", "busybox", "true")
|
||||
waitRun("test-volume-container")
|
||||
|
||||
// Observe unmount/destroy volume actions
|
||||
dockerCmd(c, "rm", "-f", "test-volume-container")
|
||||
dockerCmd(c, "volume", "rm", "test-event-volume-local")
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
out, _ := dockerCmd(c, "events", "--since", since, "--until", until)
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(events), checker.GreaterThan, 4)
|
||||
|
||||
volumeEvents := eventActionsByIDAndType(c, events, "test-event-volume-local", "volume")
|
||||
c.Assert(volumeEvents, checker.HasLen, 5)
|
||||
c.Assert(volumeEvents[0], checker.Equals, "create")
|
||||
c.Assert(volumeEvents[1], checker.Equals, "create")
|
||||
c.Assert(volumeEvents[2], checker.Equals, "mount")
|
||||
c.Assert(volumeEvents[3], checker.Equals, "unmount")
|
||||
c.Assert(volumeEvents[4], checker.Equals, "destroy")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestNetworkEvents(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
since := daemonUnixTime(c)
|
||||
|
||||
// Observe create/connect network actions
|
||||
dockerCmd(c, "network", "create", "test-event-network-local")
|
||||
dockerCmd(c, "run", "--name", "test-network-container", "--net", "test-event-network-local", "-d", "busybox", "true")
|
||||
waitRun("test-network-container")
|
||||
|
||||
// Observe disconnect/destroy network actions
|
||||
dockerCmd(c, "rm", "-f", "test-network-container")
|
||||
dockerCmd(c, "network", "rm", "test-event-network-local")
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
out, _ := dockerCmd(c, "events", "--since", since, "--until", until)
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(events), checker.GreaterThan, 4)
|
||||
|
||||
netEvents := eventActionsByIDAndType(c, events, "test-event-network-local", "network")
|
||||
c.Assert(netEvents, checker.HasLen, 4)
|
||||
c.Assert(netEvents[0], checker.Equals, "create")
|
||||
c.Assert(netEvents[1], checker.Equals, "connect")
|
||||
c.Assert(netEvents[2], checker.Equals, "disconnect")
|
||||
c.Assert(netEvents[3], checker.Equals, "destroy")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsContainerWithMultiNetwork(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// Observe create/connect network actions
|
||||
dockerCmd(c, "network", "create", "test-event-network-local-1")
|
||||
dockerCmd(c, "network", "create", "test-event-network-local-2")
|
||||
dockerCmd(c, "run", "--name", "test-network-container", "--net", "test-event-network-local-1", "-td", "busybox", "sh")
|
||||
waitRun("test-network-container")
|
||||
dockerCmd(c, "network", "connect", "test-event-network-local-2", "test-network-container")
|
||||
|
||||
since := daemonUnixTime(c)
|
||||
|
||||
dockerCmd(c, "stop", "-t", "1", "test-network-container")
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
out, _ := dockerCmd(c, "events", "--since", since, "--until", until, "-f", "type=network")
|
||||
netEvents := strings.Split(strings.TrimSpace(out), "\n")
|
||||
|
||||
// received two network disconnect events
|
||||
c.Assert(len(netEvents), checker.Equals, 2)
|
||||
c.Assert(netEvents[0], checker.Contains, "disconnect")
|
||||
c.Assert(netEvents[1], checker.Contains, "disconnect")
|
||||
|
||||
//both networks appeared in the network event output
|
||||
c.Assert(out, checker.Contains, "test-event-network-local-1")
|
||||
c.Assert(out, checker.Contains, "test-event-network-local-2")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsStreaming(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
observer, err := newEventObserver(c)
|
||||
c.Assert(err, checker.IsNil)
|
||||
err = observer.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer observer.Stop()
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox:latest", "true")
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
testActions := map[string]chan bool{
|
||||
"create": make(chan bool, 1),
|
||||
"start": make(chan bool, 1),
|
||||
"die": make(chan bool, 1),
|
||||
"destroy": make(chan bool, 1),
|
||||
}
|
||||
|
||||
matcher := matchEventLine(containerID, "container", testActions)
|
||||
processor := processEventMatch(testActions)
|
||||
go observer.Match(matcher, processor)
|
||||
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
observer.CheckEventError(c, containerID, "create", matcher)
|
||||
case <-testActions["create"]:
|
||||
// ignore, done
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
observer.CheckEventError(c, containerID, "start", matcher)
|
||||
case <-testActions["start"]:
|
||||
// ignore, done
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
observer.CheckEventError(c, containerID, "die", matcher)
|
||||
case <-testActions["die"]:
|
||||
// ignore, done
|
||||
}
|
||||
|
||||
dockerCmd(c, "rm", containerID)
|
||||
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
observer.CheckEventError(c, containerID, "destroy", matcher)
|
||||
case <-testActions["destroy"]:
|
||||
// ignore, done
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsImageUntagDelete(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
observer, err := newEventObserver(c)
|
||||
c.Assert(err, checker.IsNil)
|
||||
err = observer.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer observer.Stop()
|
||||
|
||||
name := "testimageevents"
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
|
||||
MAINTAINER "docker"`))
|
||||
imageID := getIDByName(c, name)
|
||||
c.Assert(deleteImages(name), checker.IsNil)
|
||||
|
||||
testActions := map[string]chan bool{
|
||||
"untag": make(chan bool, 1),
|
||||
"delete": make(chan bool, 1),
|
||||
}
|
||||
|
||||
matcher := matchEventLine(imageID, "image", testActions)
|
||||
processor := processEventMatch(testActions)
|
||||
go observer.Match(matcher, processor)
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
observer.CheckEventError(c, imageID, "untag", matcher)
|
||||
case <-testActions["untag"]:
|
||||
// ignore, done
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
observer.CheckEventError(c, imageID, "delete", matcher)
|
||||
case <-testActions["delete"]:
|
||||
// ignore, done
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFilterVolumeAndNetworkType(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
since := daemonUnixTime(c)
|
||||
|
||||
dockerCmd(c, "network", "create", "test-event-network-type")
|
||||
dockerCmd(c, "volume", "create", "test-event-volume-type")
|
||||
|
||||
out, _ := dockerCmd(c, "events", "--filter", "type=volume", "--filter", "type=network", "--since", since, "--until", daemonUnixTime(c))
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(events), checker.GreaterOrEqualThan, 2, check.Commentf("%s", out))
|
||||
|
||||
networkActions := eventActionsByIDAndType(c, events, "test-event-network-type", "network")
|
||||
volumeActions := eventActionsByIDAndType(c, events, "test-event-volume-type", "volume")
|
||||
|
||||
c.Assert(volumeActions[0], checker.Equals, "create")
|
||||
c.Assert(networkActions[0], checker.Equals, "create")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFilterVolumeID(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
since := daemonUnixTime(c)
|
||||
|
||||
dockerCmd(c, "volume", "create", "test-event-volume-id")
|
||||
out, _ := dockerCmd(c, "events", "--filter", "volume=test-event-volume-id", "--since", since, "--until", daemonUnixTime(c))
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(events, checker.HasLen, 1)
|
||||
|
||||
c.Assert(events[0], checker.Contains, "test-event-volume-id")
|
||||
c.Assert(events[0], checker.Contains, "driver=local")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsFilterNetworkID(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
since := daemonUnixTime(c)
|
||||
|
||||
dockerCmd(c, "network", "create", "test-event-network-local")
|
||||
out, _ := dockerCmd(c, "events", "--filter", "network=test-event-network-local", "--since", since, "--until", daemonUnixTime(c))
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(events, checker.HasLen, 1)
|
||||
|
||||
c.Assert(events[0], checker.Contains, "test-event-network-local")
|
||||
c.Assert(events[0], checker.Contains, "type=bridge")
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
// daemon config file
|
||||
configFilePath := "test.json"
|
||||
configFile, err := os.Create(configFilePath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.Remove(configFilePath)
|
||||
|
||||
daemonConfig := `{"labels":["foo=bar"]}`
|
||||
fmt.Fprintf(configFile, "%s", daemonConfig)
|
||||
configFile.Close()
|
||||
s.d.Start(c, fmt.Sprintf("--config-file=%s", configFilePath))
|
||||
|
||||
// Get daemon ID
|
||||
out, err := s.d.Cmd("info")
|
||||
c.Assert(err, checker.IsNil)
|
||||
daemonID := ""
|
||||
daemonName := ""
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
if strings.HasPrefix(line, "ID: ") {
|
||||
daemonID = strings.TrimPrefix(line, "ID: ")
|
||||
} else if strings.HasPrefix(line, "Name: ") {
|
||||
daemonName = strings.TrimPrefix(line, "Name: ")
|
||||
}
|
||||
}
|
||||
c.Assert(daemonID, checker.Not(checker.Equals), "")
|
||||
|
||||
configFile, err = os.Create(configFilePath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
daemonConfig = `{"max-concurrent-downloads":1,"labels":["bar=foo"], "shutdown-timeout": 10}`
|
||||
fmt.Fprintf(configFile, "%s", daemonConfig)
|
||||
configFile.Close()
|
||||
|
||||
c.Assert(s.d.Signal(unix.SIGHUP), checker.IsNil)
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// only check for values known (daemon ID/name) or explicitly set above,
|
||||
// otherwise just check for names being present.
|
||||
expectedSubstrings := []string{
|
||||
" daemon reload " + daemonID + " ",
|
||||
"(allow-nondistributable-artifacts=[",
|
||||
" cluster-advertise=, ",
|
||||
" cluster-store=, ",
|
||||
" cluster-store-opts=",
|
||||
" debug=true, ",
|
||||
" default-ipc-mode=",
|
||||
" default-runtime=",
|
||||
" default-shm-size=",
|
||||
" insecure-registries=[",
|
||||
" labels=[\"bar=foo\"], ",
|
||||
" live-restore=",
|
||||
" max-concurrent-downloads=1, ",
|
||||
" max-concurrent-uploads=5, ",
|
||||
" name=" + daemonName,
|
||||
" registry-mirrors=[",
|
||||
" runtimes=",
|
||||
" shutdown-timeout=10)",
|
||||
}
|
||||
|
||||
for _, s := range expectedSubstrings {
|
||||
c.Assert(out, checker.Contains, s)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestDaemonEventsWithFilters(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
// daemon config file
|
||||
configFilePath := "test.json"
|
||||
configFile, err := os.Create(configFilePath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.Remove(configFilePath)
|
||||
|
||||
daemonConfig := `{"labels":["foo=bar"]}`
|
||||
fmt.Fprintf(configFile, "%s", daemonConfig)
|
||||
configFile.Close()
|
||||
s.d.Start(c, fmt.Sprintf("--config-file=%s", configFilePath))
|
||||
|
||||
// Get daemon ID
|
||||
out, err := s.d.Cmd("info")
|
||||
c.Assert(err, checker.IsNil)
|
||||
daemonID := ""
|
||||
daemonName := ""
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
if strings.HasPrefix(line, "ID: ") {
|
||||
daemonID = strings.TrimPrefix(line, "ID: ")
|
||||
} else if strings.HasPrefix(line, "Name: ") {
|
||||
daemonName = strings.TrimPrefix(line, "Name: ")
|
||||
}
|
||||
}
|
||||
c.Assert(daemonID, checker.Not(checker.Equals), "")
|
||||
|
||||
c.Assert(s.d.Signal(unix.SIGHUP), checker.IsNil)
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", fmt.Sprintf("daemon=%s", daemonID))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s", daemonID))
|
||||
|
||||
out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", fmt.Sprintf("daemon=%s", daemonName))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s", daemonID))
|
||||
|
||||
out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", "daemon=foo")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Not(checker.Contains), fmt.Sprintf("daemon reload %s", daemonID))
|
||||
|
||||
out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", "type=daemon")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s", daemonID))
|
||||
|
||||
out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", "type=container")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Not(checker.Contains), fmt.Sprintf("daemon reload %s", daemonID))
|
||||
}
|
641
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_exec_test.go
generated
vendored
Normal file
641
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_exec_test.go
generated
vendored
Normal file
|
@ -0,0 +1,641 @@
|
|||
// +build !test_no_exec
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestExec(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top")
|
||||
c.Assert(waitRun(strings.TrimSpace(out)), check.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "exec", "testing", "cat", "/tmp/file")
|
||||
out = strings.Trim(out, "\r\n")
|
||||
c.Assert(out, checker.Equals, "test")
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecInteractive(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top")
|
||||
|
||||
execCmd := exec.Command(dockerBinary, "exec", "-i", "testing", "sh")
|
||||
stdin, err := execCmd.StdinPipe()
|
||||
c.Assert(err, checker.IsNil)
|
||||
stdout, err := execCmd.StdoutPipe()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = execCmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = stdin.Write([]byte("cat /tmp/file\n"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
r := bufio.NewReader(stdout)
|
||||
line, err := r.ReadString('\n')
|
||||
c.Assert(err, checker.IsNil)
|
||||
line = strings.TrimSpace(line)
|
||||
c.Assert(line, checker.Equals, "test")
|
||||
err = stdin.Close()
|
||||
c.Assert(err, checker.IsNil)
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
errChan <- execCmd.Wait()
|
||||
close(errChan)
|
||||
}()
|
||||
select {
|
||||
case err := <-errChan:
|
||||
c.Assert(err, checker.IsNil)
|
||||
case <-time.After(1 * time.Second):
|
||||
c.Fatal("docker exec failed to exit on stdin close")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecAfterContainerRestart(c *check.C) {
|
||||
out := runSleepingContainer(c)
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(cleanedContainerID), check.IsNil)
|
||||
dockerCmd(c, "restart", cleanedContainerID)
|
||||
c.Assert(waitRun(cleanedContainerID), check.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "exec", cleanedContainerID, "echo", "hello")
|
||||
outStr := strings.TrimSpace(out)
|
||||
c.Assert(outStr, checker.Equals, "hello")
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestExecAfterDaemonRestart(c *check.C) {
|
||||
// TODO Windows CI: Requires a little work to get this ported.
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
s.d.StartWithBusybox(c)
|
||||
|
||||
out, err := s.d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Could not run top: %s", out))
|
||||
|
||||
s.d.Restart(c)
|
||||
|
||||
out, err = s.d.Cmd("start", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Could not start top after daemon restart: %s", out))
|
||||
|
||||
out, err = s.d.Cmd("exec", "top", "echo", "hello")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Could not exec on container top: %s", out))
|
||||
|
||||
outStr := strings.TrimSpace(string(out))
|
||||
c.Assert(outStr, checker.Equals, "hello")
|
||||
}
|
||||
|
||||
// Regression test for #9155, #9044
|
||||
func (s *DockerSuite) TestExecEnv(c *check.C) {
|
||||
// TODO Windows CI: This one is interesting and may just end up being a feature
|
||||
// difference between Windows and Linux. On Windows, the environment is passed
|
||||
// into the process that is launched, not into the machine environment. Hence
|
||||
// a subsequent exec will not have LALA set/
|
||||
testRequires(c, DaemonIsLinux)
|
||||
runSleepingContainer(c, "-e", "LALA=value1", "-e", "LALA=value2", "-d", "--name", "testing")
|
||||
c.Assert(waitRun("testing"), check.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "exec", "testing", "env")
|
||||
c.Assert(out, checker.Not(checker.Contains), "LALA=value1")
|
||||
c.Assert(out, checker.Contains, "LALA=value2")
|
||||
c.Assert(out, checker.Contains, "HOME=/root")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecSetEnv(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
runSleepingContainer(c, "-e", "HOME=/root", "-d", "--name", "testing")
|
||||
c.Assert(waitRun("testing"), check.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "exec", "-e", "HOME=/another", "-e", "ABC=xyz", "testing", "env")
|
||||
c.Assert(out, checker.Not(checker.Contains), "HOME=/root")
|
||||
c.Assert(out, checker.Contains, "HOME=/another")
|
||||
c.Assert(out, checker.Contains, "ABC=xyz")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecExitStatus(c *check.C) {
|
||||
runSleepingContainer(c, "-d", "--name", "top")
|
||||
|
||||
result := icmd.RunCommand(dockerBinary, "exec", "top", "sh", "-c", "exit 23")
|
||||
result.Assert(c, icmd.Expected{ExitCode: 23, Error: "exit status 23"})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecPausedContainer(c *check.C) {
|
||||
testRequires(c, IsPausable)
|
||||
|
||||
out := runSleepingContainer(c, "-d", "--name", "testing")
|
||||
ContainerID := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "pause", "testing")
|
||||
out, _, err := dockerCmdWithError("exec", ContainerID, "echo", "hello")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("container should fail to exec new command if it is paused"))
|
||||
|
||||
expected := ContainerID + " is paused, unpause the container before exec"
|
||||
c.Assert(out, checker.Contains, expected, check.Commentf("container should not exec new command if it is paused"))
|
||||
}
|
||||
|
||||
// regression test for #9476
|
||||
func (s *DockerSuite) TestExecTTYCloseStdin(c *check.C) {
|
||||
// TODO Windows CI: This requires some work to port to Windows.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "-it", "--name", "exec_tty_stdin", "busybox")
|
||||
|
||||
cmd := exec.Command(dockerBinary, "exec", "-i", "exec_tty_stdin", "cat")
|
||||
stdinRw, err := cmd.StdinPipe()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
stdinRw.Write([]byte("test"))
|
||||
stdinRw.Close()
|
||||
|
||||
out, _, err := runCommandWithOutput(cmd)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "top", "exec_tty_stdin")
|
||||
outArr := strings.Split(out, "\n")
|
||||
c.Assert(len(outArr), checker.LessOrEqualThan, 3, check.Commentf("exec process left running"))
|
||||
c.Assert(out, checker.Not(checker.Contains), "nsenter-exec")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecTTYWithoutStdin(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "-ti", "busybox")
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), checker.IsNil)
|
||||
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
defer close(errChan)
|
||||
|
||||
cmd := exec.Command(dockerBinary, "exec", "-ti", id, "true")
|
||||
if _, err := cmd.StdinPipe(); err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
expected := "the input device is not a TTY"
|
||||
if runtime.GOOS == "windows" {
|
||||
expected += ". If you are using mintty, try prefixing the command with 'winpty'"
|
||||
}
|
||||
if out, _, err := runCommandWithOutput(cmd); err == nil {
|
||||
errChan <- fmt.Errorf("exec should have failed")
|
||||
return
|
||||
} else if !strings.Contains(out, expected) {
|
||||
errChan <- fmt.Errorf("exec failed with error %q: expected %q", out, expected)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errChan:
|
||||
c.Assert(err, check.IsNil)
|
||||
case <-time.After(3 * time.Second):
|
||||
c.Fatal("exec is running but should have failed")
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) this should be a unit tests on cli/command/container package
|
||||
func (s *DockerSuite) TestExecParseError(c *check.C) {
|
||||
// TODO Windows CI: Requires some extra work. Consider copying the
|
||||
// runSleepingContainer helper to have an exec version.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "--name", "top", "busybox", "top")
|
||||
|
||||
// Test normal (non-detached) case first
|
||||
icmd.RunCommand(dockerBinary, "exec", "top").Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Error: "exit status 1",
|
||||
Err: "See 'docker exec --help'",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecStopNotHanging(c *check.C) {
|
||||
// TODO Windows CI: Requires some extra work. Consider copying the
|
||||
// runSleepingContainer helper to have an exec version.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "top")
|
||||
|
||||
result := icmd.StartCmd(icmd.Command(dockerBinary, "exec", "testing", "top"))
|
||||
result.Assert(c, icmd.Success)
|
||||
go icmd.WaitOnCmd(0, result)
|
||||
|
||||
type dstop struct {
|
||||
out string
|
||||
err error
|
||||
}
|
||||
ch := make(chan dstop)
|
||||
go func() {
|
||||
result := icmd.RunCommand(dockerBinary, "stop", "testing")
|
||||
ch <- dstop{result.Combined(), result.Error}
|
||||
close(ch)
|
||||
}()
|
||||
select {
|
||||
case <-time.After(3 * time.Second):
|
||||
c.Fatal("Container stop timed out")
|
||||
case s := <-ch:
|
||||
c.Assert(s.err, check.IsNil)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecCgroup(c *check.C) {
|
||||
// Not applicable on Windows - using Linux specific functionality
|
||||
testRequires(c, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "top")
|
||||
|
||||
out, _ := dockerCmd(c, "exec", "testing", "cat", "/proc/1/cgroup")
|
||||
containerCgroups := sort.StringSlice(strings.Split(out, "\n"))
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var mu sync.Mutex
|
||||
var execCgroups []sort.StringSlice
|
||||
errChan := make(chan error)
|
||||
// exec a few times concurrently to get consistent failure
|
||||
for i := 0; i < 5; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
out, _, err := dockerCmdWithError("exec", "testing", "cat", "/proc/self/cgroup")
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
cg := sort.StringSlice(strings.Split(out, "\n"))
|
||||
|
||||
mu.Lock()
|
||||
execCgroups = append(execCgroups, cg)
|
||||
mu.Unlock()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
close(errChan)
|
||||
|
||||
for err := range errChan {
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
for _, cg := range execCgroups {
|
||||
if !reflect.DeepEqual(cg, containerCgroups) {
|
||||
fmt.Println("exec cgroups:")
|
||||
for _, name := range cg {
|
||||
fmt.Printf(" %s\n", name)
|
||||
}
|
||||
|
||||
fmt.Println("container cgroups:")
|
||||
for _, name := range containerCgroups {
|
||||
fmt.Printf(" %s\n", name)
|
||||
}
|
||||
c.Fatal("cgroups mismatched")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecInspectID(c *check.C) {
|
||||
out := runSleepingContainer(c, "-d")
|
||||
id := strings.TrimSuffix(out, "\n")
|
||||
|
||||
out = inspectField(c, id, "ExecIDs")
|
||||
c.Assert(out, checker.Equals, "[]", check.Commentf("ExecIDs should be empty, got: %s", out))
|
||||
|
||||
// Start an exec, have it block waiting so we can do some checking
|
||||
cmd := exec.Command(dockerBinary, "exec", id, "sh", "-c",
|
||||
"while ! test -e /execid1; do sleep 1; done")
|
||||
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to start the exec cmd"))
|
||||
|
||||
// Give the exec 10 chances/seconds to start then give up and stop the test
|
||||
tries := 10
|
||||
for i := 0; i < tries; i++ {
|
||||
// Since its still running we should see exec as part of the container
|
||||
out = strings.TrimSpace(inspectField(c, id, "ExecIDs"))
|
||||
|
||||
if out != "[]" && out != "<no value>" {
|
||||
break
|
||||
}
|
||||
c.Assert(i+1, checker.Not(checker.Equals), tries, check.Commentf("ExecIDs still empty after 10 second"))
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
// Save execID for later
|
||||
execID, err := inspectFilter(id, "index .ExecIDs 0")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to get the exec id"))
|
||||
|
||||
// End the exec by creating the missing file
|
||||
err = exec.Command(dockerBinary, "exec", id,
|
||||
"sh", "-c", "touch /execid1").Run()
|
||||
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to run the 2nd exec cmd"))
|
||||
|
||||
// Wait for 1st exec to complete
|
||||
cmd.Wait()
|
||||
|
||||
// Give the exec 10 chances/seconds to stop then give up and stop the test
|
||||
for i := 0; i < tries; i++ {
|
||||
// Since its still running we should see exec as part of the container
|
||||
out = strings.TrimSpace(inspectField(c, id, "ExecIDs"))
|
||||
|
||||
if out == "[]" {
|
||||
break
|
||||
}
|
||||
c.Assert(i+1, checker.Not(checker.Equals), tries, check.Commentf("ExecIDs still not empty after 10 second"))
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
// But we should still be able to query the execID
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
_, err = cli.ContainerExecInspect(context.Background(), execID)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Now delete the container and then an 'inspect' on the exec should
|
||||
// result in a 404 (not 'container not running')
|
||||
out, ec := dockerCmd(c, "rm", "-f", id)
|
||||
c.Assert(ec, checker.Equals, 0, check.Commentf("error removing container: %s", out))
|
||||
|
||||
_, err = cli.ContainerExecInspect(context.Background(), execID)
|
||||
expected := "No such exec instance"
|
||||
c.Assert(err.Error(), checker.Contains, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksPingLinkedContainersOnRename(c *check.C) {
|
||||
// Problematic on Windows as Windows does not support links
|
||||
testRequires(c, DaemonIsLinux)
|
||||
var out string
|
||||
out, _ = dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
|
||||
idA := strings.TrimSpace(out)
|
||||
c.Assert(idA, checker.Not(checker.Equals), "", check.Commentf("%s, id should not be nil", out))
|
||||
out, _ = dockerCmd(c, "run", "-d", "--link", "container1:alias1", "--name", "container2", "busybox", "top")
|
||||
idB := strings.TrimSpace(out)
|
||||
c.Assert(idB, checker.Not(checker.Equals), "", check.Commentf("%s, id should not be nil", out))
|
||||
|
||||
dockerCmd(c, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
|
||||
dockerCmd(c, "rename", "container1", "container_new")
|
||||
dockerCmd(c, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRunMutableNetworkFiles(c *check.C) {
|
||||
// Not applicable on Windows to Windows CI.
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
for _, fn := range []string{"resolv.conf", "hosts"} {
|
||||
containers := cli.DockerCmd(c, "ps", "-q", "-a").Combined()
|
||||
if containers != "" {
|
||||
cli.DockerCmd(c, append([]string{"rm", "-fv"}, strings.Split(strings.TrimSpace(containers), "\n")...)...)
|
||||
}
|
||||
|
||||
content := runCommandAndReadContainerFile(c, fn, dockerBinary, "run", "-d", "--name", "c1", "busybox", "sh", "-c", fmt.Sprintf("echo success >/etc/%s && top", fn))
|
||||
|
||||
c.Assert(strings.TrimSpace(string(content)), checker.Equals, "success", check.Commentf("Content was not what was modified in the container", string(content)))
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top")
|
||||
contID := strings.TrimSpace(out)
|
||||
netFilePath := containerStorageFile(contID, fn)
|
||||
|
||||
f, err := os.OpenFile(netFilePath, os.O_WRONLY|os.O_SYNC|os.O_APPEND, 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
if _, err := f.Seek(0, 0); err != nil {
|
||||
f.Close()
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
if err := f.Truncate(0); err != nil {
|
||||
f.Close()
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := f.Write([]byte("success2\n")); err != nil {
|
||||
f.Close()
|
||||
c.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
res, _ := dockerCmd(c, "exec", contID, "cat", "/etc/"+fn)
|
||||
c.Assert(res, checker.Equals, "success2\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecWithUser(c *check.C) {
|
||||
// TODO Windows CI: This may be fixable in the future once Windows
|
||||
// supports users
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "--name", "parent", "busybox", "top")
|
||||
|
||||
out, _ := dockerCmd(c, "exec", "-u", "1", "parent", "id")
|
||||
c.Assert(out, checker.Contains, "uid=1(daemon) gid=1(daemon)")
|
||||
|
||||
out, _ = dockerCmd(c, "exec", "-u", "root", "parent", "id")
|
||||
c.Assert(out, checker.Contains, "uid=0(root) gid=0(root)", check.Commentf("exec with user by id expected daemon user got %s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecWithPrivileged(c *check.C) {
|
||||
// Not applicable on Windows
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
// Start main loop which attempts mknod repeatedly
|
||||
dockerCmd(c, "run", "-d", "--name", "parent", "--cap-drop=ALL", "busybox", "sh", "-c", `while (true); do if [ -e /exec_priv ]; then cat /exec_priv && mknod /tmp/sda b 8 0 && echo "Success"; else echo "Privileged exec has not run yet"; fi; usleep 10000; done`)
|
||||
|
||||
// Check exec mknod doesn't work
|
||||
icmd.RunCommand(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sdb b 8 16").Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: "Operation not permitted",
|
||||
})
|
||||
|
||||
// Check exec mknod does work with --privileged
|
||||
result := icmd.RunCommand(dockerBinary, "exec", "--privileged", "parent", "sh", "-c", `echo "Running exec --privileged" > /exec_priv && mknod /tmp/sdb b 8 16 && usleep 50000 && echo "Finished exec --privileged" > /exec_priv && echo ok`)
|
||||
result.Assert(c, icmd.Success)
|
||||
|
||||
actual := strings.TrimSpace(result.Combined())
|
||||
c.Assert(actual, checker.Equals, "ok", check.Commentf("exec mknod in --cap-drop=ALL container with --privileged failed, output: %q", result.Combined()))
|
||||
|
||||
// Check subsequent unprivileged exec cannot mknod
|
||||
icmd.RunCommand(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sdc b 8 32").Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: "Operation not permitted",
|
||||
})
|
||||
// Confirm at no point was mknod allowed
|
||||
result = icmd.RunCommand(dockerBinary, "logs", "parent")
|
||||
result.Assert(c, icmd.Success)
|
||||
c.Assert(result.Combined(), checker.Not(checker.Contains), "Success")
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecWithImageUser(c *check.C) {
|
||||
// Not applicable on Windows
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "testbuilduser"
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
|
||||
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
|
||||
USER dockerio`))
|
||||
dockerCmd(c, "run", "-d", "--name", "dockerioexec", name, "top")
|
||||
|
||||
out, _ := dockerCmd(c, "exec", "dockerioexec", "whoami")
|
||||
c.Assert(out, checker.Contains, "dockerio", check.Commentf("exec with user by id expected dockerio user got %s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecOnReadonlyContainer(c *check.C) {
|
||||
// Windows does not support read-only
|
||||
// --read-only + userns has remount issues
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
dockerCmd(c, "run", "-d", "--read-only", "--name", "parent", "busybox", "top")
|
||||
dockerCmd(c, "exec", "parent", "true")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecUlimits(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "testexeculimits"
|
||||
runSleepingContainer(c, "-d", "--ulimit", "nofile=511:511", "--name", name)
|
||||
c.Assert(waitRun(name), checker.IsNil)
|
||||
|
||||
out, _, err := dockerCmdWithError("exec", name, "sh", "-c", "ulimit -n")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "511")
|
||||
}
|
||||
|
||||
// #15750
|
||||
func (s *DockerSuite) TestExecStartFails(c *check.C) {
|
||||
// TODO Windows CI. This test should be portable. Figure out why it fails
|
||||
// currently.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "exec-15750"
|
||||
runSleepingContainer(c, "-d", "--name", name)
|
||||
c.Assert(waitRun(name), checker.IsNil)
|
||||
|
||||
out, _, err := dockerCmdWithError("exec", name, "no-such-cmd")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "executable file not found")
|
||||
}
|
||||
|
||||
// Fix regression in https://github.com/docker/docker/pull/26461#issuecomment-250287297
|
||||
func (s *DockerSuite) TestExecWindowsPathNotWiped(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows)
|
||||
out, _ := dockerCmd(c, "run", "-d", "--name", "testing", minimalBaseImage(), "powershell", "start-sleep", "60")
|
||||
c.Assert(waitRun(strings.TrimSpace(out)), check.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "exec", "testing", "powershell", "write-host", "$env:PATH")
|
||||
out = strings.ToLower(strings.Trim(out, "\r\n"))
|
||||
c.Assert(out, checker.Contains, `windowspowershell\v1.0`)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecEnvLinksHost(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
runSleepingContainer(c, "-d", "--name", "foo")
|
||||
runSleepingContainer(c, "-d", "--link", "foo:db", "--hostname", "myhost", "--name", "bar")
|
||||
out, _ := dockerCmd(c, "exec", "bar", "env")
|
||||
c.Assert(out, checker.Contains, "HOSTNAME=myhost")
|
||||
c.Assert(out, checker.Contains, "DB_NAME=/bar/db")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecWindowsOpenHandles(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows)
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
v, err := kernel.GetKernelVersion()
|
||||
c.Assert(err, checker.IsNil)
|
||||
build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0])
|
||||
if build >= 17743 {
|
||||
c.Skip("Temporarily disabled on RS5 17743+ builds due to platform bug")
|
||||
|
||||
// This is being tracked internally. @jhowardmsft. Summary of failure
|
||||
// from an email in early July 2018 below:
|
||||
//
|
||||
// Platform regression. In cmd.exe by the look of it. I can repro
|
||||
// it outside of CI. It fails the same on 17681, 17676 and even as
|
||||
// far back as 17663, over a month old. From investigating, I can see
|
||||
// what's happening in the container, but not the reason. The test
|
||||
// starts a long-running container based on the Windows busybox image.
|
||||
// It then adds another process (docker exec) to that container to
|
||||
// sleep. It loops waiting for two instances of busybox.exe running,
|
||||
// and cmd.exe to quit. What's actually happening is that the second
|
||||
// exec hangs indefinitely, and from docker top, I can see
|
||||
// "OpenWith.exe" running.
|
||||
|
||||
//Manual repro would be
|
||||
//# Start the first long-running container
|
||||
//docker run --rm -d --name test busybox sleep 300
|
||||
|
||||
//# In another window, docker top test. There should be a single instance of busybox.exe running
|
||||
//# In a third window, docker exec test cmd /c start sleep 10 NOTE THIS HANGS UNTIL 5 MIN TIMEOUT
|
||||
//# In the second window, run docker top test. Note that OpenWith.exe is running, one cmd.exe and only one busybox. I would expect no "OpenWith" and two busybox.exe's.
|
||||
}
|
||||
}
|
||||
|
||||
runSleepingContainer(c, "-d", "--name", "test")
|
||||
exec := make(chan bool)
|
||||
go func() {
|
||||
dockerCmd(c, "exec", "test", "cmd", "/c", "start sleep 10")
|
||||
exec <- true
|
||||
}()
|
||||
|
||||
count := 0
|
||||
for {
|
||||
top := make(chan string)
|
||||
var out string
|
||||
go func() {
|
||||
out, _ := dockerCmd(c, "top", "test")
|
||||
top <- out
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(time.Second * 5):
|
||||
c.Fatal("timed out waiting for top while exec is exiting")
|
||||
case out = <-top:
|
||||
break
|
||||
}
|
||||
|
||||
if strings.Count(out, "busybox.exe") == 2 && !strings.Contains(out, "cmd.exe") {
|
||||
// The initial exec process (cmd.exe) has exited, and both sleeps are currently running
|
||||
break
|
||||
}
|
||||
count++
|
||||
if count >= 30 {
|
||||
c.Fatal("too many retries")
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
inspect := make(chan bool)
|
||||
go func() {
|
||||
dockerCmd(c, "inspect", "test")
|
||||
inspect <- true
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(time.Second * 5):
|
||||
c.Fatal("timed out waiting for inspect while exec is exiting")
|
||||
case <-inspect:
|
||||
break
|
||||
}
|
||||
|
||||
// Ensure the background sleep is still running
|
||||
out, _ := dockerCmd(c, "top", "test")
|
||||
c.Assert(strings.Count(out, "busybox.exe"), checker.Equals, 2)
|
||||
|
||||
// The exec should exit when the background sleep exits
|
||||
select {
|
||||
case <-time.After(time.Second * 15):
|
||||
c.Fatal("timed out waiting for async exec to exit")
|
||||
case <-exec:
|
||||
// Ensure the background sleep has actually exited
|
||||
out, _ := dockerCmd(c, "top", "test")
|
||||
c.Assert(strings.Count(out, "busybox.exe"), checker.Equals, 1)
|
||||
break
|
||||
}
|
||||
}
|
97
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_exec_unix_test.go
generated
vendored
Normal file
97
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_exec_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
// +build !windows,!test_no_exec
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"github.com/kr/pty"
|
||||
)
|
||||
|
||||
// regression test for #12546
|
||||
func (s *DockerSuite) TestExecInteractiveStdinClose(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-itd", "busybox", "/bin/cat")
|
||||
contID := strings.TrimSpace(out)
|
||||
|
||||
cmd := exec.Command(dockerBinary, "exec", "-i", contID, "echo", "-n", "hello")
|
||||
p, err := pty.Start(cmd)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
b := bytes.NewBuffer(nil)
|
||||
|
||||
ch := make(chan error)
|
||||
go func() { ch <- cmd.Wait() }()
|
||||
|
||||
select {
|
||||
case err := <-ch:
|
||||
c.Assert(err, checker.IsNil)
|
||||
io.Copy(b, p)
|
||||
p.Close()
|
||||
bs := b.Bytes()
|
||||
bs = bytes.Trim(bs, "\x00")
|
||||
output := string(bs[:])
|
||||
c.Assert(strings.TrimSpace(output), checker.Equals, "hello")
|
||||
case <-time.After(5 * time.Second):
|
||||
p.Close()
|
||||
c.Fatal("timed out running docker exec")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestExecTTY(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
dockerCmd(c, "run", "-d", "--name=test", "busybox", "sh", "-c", "echo hello > /foo && top")
|
||||
|
||||
cmd := exec.Command(dockerBinary, "exec", "-it", "test", "sh")
|
||||
p, err := pty.Start(cmd)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer p.Close()
|
||||
|
||||
_, err = p.Write([]byte("cat /foo && exit\n"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
chErr := make(chan error)
|
||||
go func() {
|
||||
chErr <- cmd.Wait()
|
||||
}()
|
||||
select {
|
||||
case err := <-chErr:
|
||||
c.Assert(err, checker.IsNil)
|
||||
case <-time.After(3 * time.Second):
|
||||
c.Fatal("timeout waiting for exec to exit")
|
||||
}
|
||||
|
||||
buf := make([]byte, 256)
|
||||
read, err := p.Read(buf)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(bytes.Contains(buf, []byte("hello")), checker.Equals, true, check.Commentf(string(buf[:read])))
|
||||
}
|
||||
|
||||
// Test the TERM env var is set when -t is provided on exec
|
||||
func (s *DockerSuite) TestExecWithTERM(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
out, _ := dockerCmd(c, "run", "-id", "busybox", "/bin/cat")
|
||||
contID := strings.TrimSpace(out)
|
||||
cmd := exec.Command(dockerBinary, "exec", "-t", contID, "sh", "-c", "if [ -z $TERM ]; then exit 1; else exit 0; fi")
|
||||
if err := cmd.Run(); err != nil {
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the TERM env var is not set on exec when -t is not provided, even if it was set
|
||||
// on run
|
||||
func (s *DockerSuite) TestExecWithNoTERM(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
out, _ := dockerCmd(c, "run", "-itd", "busybox", "/bin/cat")
|
||||
contID := strings.TrimSpace(out)
|
||||
cmd := exec.Command(dockerBinary, "exec", contID, "sh", "-c", "if [ -z $TERM ]; then exit 0; else exit 1; fi")
|
||||
if err := cmd.Run(); err != nil {
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
}
|
34
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_export_import_test.go
generated
vendored
Normal file
34
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_export_import_test.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// TODO: Move this test to docker/cli, as it is essentially the same test
|
||||
// as TestExportContainerAndImportImage except output to a file.
|
||||
// Used to test output flag in the export command
|
||||
func (s *DockerSuite) TestExportContainerWithOutputAndImportImage(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
containerID := "testexportcontainerwithoutputandimportimage"
|
||||
|
||||
dockerCmd(c, "run", "--name", containerID, "busybox", "true")
|
||||
dockerCmd(c, "export", "--output=testexp.tar", containerID)
|
||||
defer os.Remove("testexp.tar")
|
||||
|
||||
resultCat := icmd.RunCommand("cat", "testexp.tar")
|
||||
resultCat.Assert(c, icmd.Success)
|
||||
|
||||
result := icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "import", "-", "repo/testexp:v1"},
|
||||
Stdin: strings.NewReader(resultCat.Combined()),
|
||||
})
|
||||
result.Assert(c, icmd.Success)
|
||||
|
||||
cleanedImageID := strings.TrimSpace(result.Combined())
|
||||
c.Assert(cleanedImageID, checker.Not(checker.Equals), "", check.Commentf("output should have been an image id"))
|
||||
}
|
631
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_external_volume_driver_unix_test.go
generated
vendored
Normal file
631
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_external_volume_driver_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,631 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
testdaemon "github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
const volumePluginName = "test-external-volume-driver"
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerExternalVolumeSuite{
|
||||
ds: &DockerSuite{},
|
||||
})
|
||||
}
|
||||
|
||||
type eventCounter struct {
|
||||
activations int
|
||||
creations int
|
||||
removals int
|
||||
mounts int
|
||||
unmounts int
|
||||
paths int
|
||||
lists int
|
||||
gets int
|
||||
caps int
|
||||
}
|
||||
|
||||
type DockerExternalVolumeSuite struct {
|
||||
ds *DockerSuite
|
||||
d *daemon.Daemon
|
||||
*volumePlugin
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) SetUpTest(c *check.C) {
|
||||
testRequires(c, SameHostDaemon)
|
||||
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
s.ec = &eventCounter{}
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TearDownTest(c *check.C) {
|
||||
if s.d != nil {
|
||||
s.d.Stop(c)
|
||||
s.ds.TearDownTest(c)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
|
||||
s.volumePlugin = newVolumePlugin(c, volumePluginName)
|
||||
}
|
||||
|
||||
type volumePlugin struct {
|
||||
ec *eventCounter
|
||||
*httptest.Server
|
||||
vols map[string]vol
|
||||
}
|
||||
|
||||
type vol struct {
|
||||
Name string
|
||||
Mountpoint string
|
||||
Ninja bool // hack used to trigger a null volume return on `Get`
|
||||
Status map[string]interface{}
|
||||
Options map[string]string
|
||||
}
|
||||
|
||||
func (p *volumePlugin) Close() {
|
||||
p.Server.Close()
|
||||
}
|
||||
|
||||
func newVolumePlugin(c *check.C, name string) *volumePlugin {
|
||||
mux := http.NewServeMux()
|
||||
s := &volumePlugin{Server: httptest.NewServer(mux), ec: &eventCounter{}, vols: make(map[string]vol)}
|
||||
|
||||
type pluginRequest struct {
|
||||
Name string
|
||||
Opts map[string]string
|
||||
ID string
|
||||
}
|
||||
|
||||
type pluginResp struct {
|
||||
Mountpoint string `json:",omitempty"`
|
||||
Err string `json:",omitempty"`
|
||||
}
|
||||
|
||||
read := func(b io.ReadCloser) (pluginRequest, error) {
|
||||
defer b.Close()
|
||||
var pr pluginRequest
|
||||
err := json.NewDecoder(b).Decode(&pr)
|
||||
return pr, err
|
||||
}
|
||||
|
||||
send := func(w http.ResponseWriter, data interface{}) {
|
||||
switch t := data.(type) {
|
||||
case error:
|
||||
http.Error(w, t.Error(), 500)
|
||||
case string:
|
||||
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
||||
fmt.Fprintln(w, t)
|
||||
default:
|
||||
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
||||
json.NewEncoder(w).Encode(&data)
|
||||
}
|
||||
}
|
||||
|
||||
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.ec.activations++
|
||||
send(w, `{"Implements": ["VolumeDriver"]}`)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/VolumeDriver.Create", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.ec.creations++
|
||||
pr, err := read(r.Body)
|
||||
if err != nil {
|
||||
send(w, err)
|
||||
return
|
||||
}
|
||||
_, isNinja := pr.Opts["ninja"]
|
||||
status := map[string]interface{}{"Hello": "world"}
|
||||
s.vols[pr.Name] = vol{Name: pr.Name, Ninja: isNinja, Status: status, Options: pr.Opts}
|
||||
send(w, nil)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/VolumeDriver.List", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.ec.lists++
|
||||
vols := make([]vol, 0, len(s.vols))
|
||||
for _, v := range s.vols {
|
||||
if v.Ninja {
|
||||
continue
|
||||
}
|
||||
vols = append(vols, v)
|
||||
}
|
||||
send(w, map[string][]vol{"Volumes": vols})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/VolumeDriver.Get", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.ec.gets++
|
||||
pr, err := read(r.Body)
|
||||
if err != nil {
|
||||
send(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
v, exists := s.vols[pr.Name]
|
||||
if !exists {
|
||||
send(w, `{"Err": "no such volume"}`)
|
||||
}
|
||||
|
||||
if v.Ninja {
|
||||
send(w, map[string]vol{})
|
||||
return
|
||||
}
|
||||
|
||||
v.Mountpoint = hostVolumePath(pr.Name)
|
||||
send(w, map[string]vol{"Volume": v})
|
||||
return
|
||||
})
|
||||
|
||||
mux.HandleFunc("/VolumeDriver.Remove", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.ec.removals++
|
||||
pr, err := read(r.Body)
|
||||
if err != nil {
|
||||
send(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
v, ok := s.vols[pr.Name]
|
||||
if !ok {
|
||||
send(w, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(hostVolumePath(v.Name)); err != nil {
|
||||
send(w, &pluginResp{Err: err.Error()})
|
||||
return
|
||||
}
|
||||
delete(s.vols, v.Name)
|
||||
send(w, nil)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/VolumeDriver.Path", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.ec.paths++
|
||||
|
||||
pr, err := read(r.Body)
|
||||
if err != nil {
|
||||
send(w, err)
|
||||
return
|
||||
}
|
||||
p := hostVolumePath(pr.Name)
|
||||
send(w, &pluginResp{Mountpoint: p})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/VolumeDriver.Mount", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.ec.mounts++
|
||||
|
||||
pr, err := read(r.Body)
|
||||
if err != nil {
|
||||
send(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if v, exists := s.vols[pr.Name]; exists {
|
||||
// Use this to simulate a mount failure
|
||||
if _, exists := v.Options["invalidOption"]; exists {
|
||||
send(w, fmt.Errorf("invalid argument"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
p := hostVolumePath(pr.Name)
|
||||
if err := os.MkdirAll(p, 0755); err != nil {
|
||||
send(w, &pluginResp{Err: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(p, "test"), []byte(s.Server.URL), 0644); err != nil {
|
||||
send(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(p, "mountID"), []byte(pr.ID), 0644); err != nil {
|
||||
send(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
send(w, &pluginResp{Mountpoint: p})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/VolumeDriver.Unmount", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.ec.unmounts++
|
||||
|
||||
_, err := read(r.Body)
|
||||
if err != nil {
|
||||
send(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
send(w, nil)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/VolumeDriver.Capabilities", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.ec.caps++
|
||||
|
||||
_, err := read(r.Body)
|
||||
if err != nil {
|
||||
send(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
send(w, `{"Capabilities": { "Scope": "global" }}`)
|
||||
})
|
||||
|
||||
err := os.MkdirAll("/etc/docker/plugins", 0755)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = ioutil.WriteFile("/etc/docker/plugins/"+name+".spec", []byte(s.Server.URL), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TearDownSuite(c *check.C) {
|
||||
s.volumePlugin.Close()
|
||||
|
||||
err := os.RemoveAll("/etc/docker/plugins")
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestVolumeCLICreateOptionConflict(c *check.C) {
|
||||
dockerCmd(c, "volume", "create", "test")
|
||||
|
||||
out, _, err := dockerCmdWithError("volume", "create", "test", "--driver", volumePluginName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("volume create exception name already in use with another driver"))
|
||||
c.Assert(out, checker.Contains, "must be unique")
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Driver }}", "test")
|
||||
_, _, err = dockerCmdWithError("volume", "create", "test", "--driver", strings.TrimSpace(out))
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverNamed(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
|
||||
out, err := s.d.Cmd("run", "--rm", "--name", "test-data", "-v", "external-volume-test:/tmp/external-volume-test", "--volume-driver", volumePluginName, "busybox:latest", "cat", "/tmp/external-volume-test/test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, s.Server.URL)
|
||||
|
||||
_, err = s.d.Cmd("volume", "rm", "external-volume-test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
p := hostVolumePath("external-volume-test")
|
||||
_, err = os.Lstat(p)
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(os.IsNotExist(err), checker.True, check.Commentf("Expected volume path in host to not exist: %s, %v\n", p, err))
|
||||
|
||||
c.Assert(s.ec.activations, checker.Equals, 1)
|
||||
c.Assert(s.ec.creations, checker.Equals, 1)
|
||||
c.Assert(s.ec.removals, checker.Equals, 1)
|
||||
c.Assert(s.ec.mounts, checker.Equals, 1)
|
||||
c.Assert(s.ec.unmounts, checker.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnnamed(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
|
||||
out, err := s.d.Cmd("run", "--rm", "--name", "test-data", "-v", "/tmp/external-volume-test", "--volume-driver", volumePluginName, "busybox:latest", "cat", "/tmp/external-volume-test/test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, s.Server.URL)
|
||||
|
||||
c.Assert(s.ec.activations, checker.Equals, 1)
|
||||
c.Assert(s.ec.creations, checker.Equals, 1)
|
||||
c.Assert(s.ec.removals, checker.Equals, 1)
|
||||
c.Assert(s.ec.mounts, checker.Equals, 1)
|
||||
c.Assert(s.ec.unmounts, checker.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverVolumesFrom(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
|
||||
out, err := s.d.Cmd("run", "--name", "vol-test1", "-v", "/foo", "--volume-driver", volumePluginName, "busybox:latest")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = s.d.Cmd("run", "--rm", "--volumes-from", "vol-test1", "--name", "vol-test2", "busybox", "ls", "/tmp")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = s.d.Cmd("rm", "-fv", "vol-test1")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
c.Assert(s.ec.activations, checker.Equals, 1)
|
||||
c.Assert(s.ec.creations, checker.Equals, 1)
|
||||
c.Assert(s.ec.removals, checker.Equals, 1)
|
||||
c.Assert(s.ec.mounts, checker.Equals, 2)
|
||||
c.Assert(s.ec.unmounts, checker.Equals, 2)
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverDeleteContainer(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
|
||||
out, err := s.d.Cmd("run", "--name", "vol-test1", "-v", "/foo", "--volume-driver", volumePluginName, "busybox:latest")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = s.d.Cmd("rm", "-fv", "vol-test1")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
c.Assert(s.ec.activations, checker.Equals, 1)
|
||||
c.Assert(s.ec.creations, checker.Equals, 1)
|
||||
c.Assert(s.ec.removals, checker.Equals, 1)
|
||||
c.Assert(s.ec.mounts, checker.Equals, 1)
|
||||
c.Assert(s.ec.unmounts, checker.Equals, 1)
|
||||
}
|
||||
|
||||
func hostVolumePath(name string) string {
|
||||
return fmt.Sprintf("/var/lib/docker/volumes/%s", name)
|
||||
}
|
||||
|
||||
// Make sure a request to use a down driver doesn't block other requests
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverLookupNotBlocked(c *check.C) {
|
||||
specPath := "/etc/docker/plugins/down-driver.spec"
|
||||
err := ioutil.WriteFile(specPath, []byte("tcp://127.0.0.7:9999"), 0644)
|
||||
c.Assert(err, check.IsNil)
|
||||
defer os.RemoveAll(specPath)
|
||||
|
||||
chCmd1 := make(chan struct{})
|
||||
chCmd2 := make(chan error)
|
||||
cmd1 := exec.Command(dockerBinary, "volume", "create", "-d", "down-driver")
|
||||
cmd2 := exec.Command(dockerBinary, "volume", "create")
|
||||
|
||||
c.Assert(cmd1.Start(), checker.IsNil)
|
||||
defer cmd1.Process.Kill()
|
||||
time.Sleep(100 * time.Millisecond) // ensure API has been called
|
||||
c.Assert(cmd2.Start(), checker.IsNil)
|
||||
|
||||
go func() {
|
||||
cmd1.Wait()
|
||||
close(chCmd1)
|
||||
}()
|
||||
go func() {
|
||||
chCmd2 <- cmd2.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-chCmd1:
|
||||
cmd2.Process.Kill()
|
||||
c.Fatalf("volume create with down driver finished unexpectedly")
|
||||
case err := <-chCmd2:
|
||||
c.Assert(err, checker.IsNil)
|
||||
case <-time.After(5 * time.Second):
|
||||
cmd2.Process.Kill()
|
||||
c.Fatal("volume creates are blocked by previous create requests when previous driver is down")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverRetryNotImmediatelyExists(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
driverName := "test-external-volume-driver-retry"
|
||||
|
||||
errchan := make(chan error)
|
||||
started := make(chan struct{})
|
||||
go func() {
|
||||
close(started)
|
||||
if out, err := s.d.Cmd("run", "--rm", "--name", "test-data-retry", "-v", "external-volume-test:/tmp/external-volume-test", "--volume-driver", driverName, "busybox:latest"); err != nil {
|
||||
errchan <- fmt.Errorf("%v:\n%s", err, out)
|
||||
}
|
||||
close(errchan)
|
||||
}()
|
||||
|
||||
<-started
|
||||
// wait for a retry to occur, then create spec to allow plugin to register
|
||||
time.Sleep(2 * time.Second)
|
||||
p := newVolumePlugin(c, driverName)
|
||||
defer p.Close()
|
||||
|
||||
select {
|
||||
case err := <-errchan:
|
||||
c.Assert(err, checker.IsNil)
|
||||
case <-time.After(8 * time.Second):
|
||||
c.Fatal("volume creates fail when plugin not immediately available")
|
||||
}
|
||||
|
||||
_, err := s.d.Cmd("volume", "rm", "external-volume-test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(p.ec.activations, checker.Equals, 1)
|
||||
c.Assert(p.ec.creations, checker.Equals, 1)
|
||||
c.Assert(p.ec.removals, checker.Equals, 1)
|
||||
c.Assert(p.ec.mounts, checker.Equals, 1)
|
||||
c.Assert(p.ec.unmounts, checker.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverBindExternalVolume(c *check.C) {
|
||||
dockerCmd(c, "volume", "create", "-d", volumePluginName, "foo")
|
||||
dockerCmd(c, "run", "-d", "--name", "testing", "-v", "foo:/bar", "busybox", "top")
|
||||
|
||||
var mounts []struct {
|
||||
Name string
|
||||
Driver string
|
||||
}
|
||||
out := inspectFieldJSON(c, "testing", "Mounts")
|
||||
c.Assert(json.NewDecoder(strings.NewReader(out)).Decode(&mounts), checker.IsNil)
|
||||
c.Assert(len(mounts), checker.Equals, 1, check.Commentf("%s", out))
|
||||
c.Assert(mounts[0].Name, checker.Equals, "foo")
|
||||
c.Assert(mounts[0].Driver, checker.Equals, volumePluginName)
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverList(c *check.C) {
|
||||
dockerCmd(c, "volume", "create", "-d", volumePluginName, "abc3")
|
||||
out, _ := dockerCmd(c, "volume", "ls")
|
||||
ls := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(ls), check.Equals, 2, check.Commentf("\n%s", out))
|
||||
|
||||
vol := strings.Fields(ls[len(ls)-1])
|
||||
c.Assert(len(vol), check.Equals, 2, check.Commentf("%v", vol))
|
||||
c.Assert(vol[0], check.Equals, volumePluginName)
|
||||
c.Assert(vol[1], check.Equals, "abc3")
|
||||
|
||||
c.Assert(s.ec.lists, check.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverGet(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("volume", "inspect", "dummy")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "No such volume")
|
||||
c.Assert(s.ec.gets, check.Equals, 1)
|
||||
|
||||
dockerCmd(c, "volume", "create", "test", "-d", volumePluginName)
|
||||
out, _ = dockerCmd(c, "volume", "inspect", "test")
|
||||
|
||||
type vol struct {
|
||||
Status map[string]string
|
||||
}
|
||||
var st []vol
|
||||
|
||||
c.Assert(json.Unmarshal([]byte(out), &st), checker.IsNil)
|
||||
c.Assert(st, checker.HasLen, 1)
|
||||
c.Assert(st[0].Status, checker.HasLen, 1, check.Commentf("%v", st[0]))
|
||||
c.Assert(st[0].Status["Hello"], checker.Equals, "world", check.Commentf("%v", st[0].Status))
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverWithDaemonRestart(c *check.C) {
|
||||
dockerCmd(c, "volume", "create", "-d", volumePluginName, "abc1")
|
||||
s.d.Restart(c)
|
||||
|
||||
dockerCmd(c, "run", "--name=test", "-v", "abc1:/foo", "busybox", "true")
|
||||
var mounts []types.MountPoint
|
||||
inspectFieldAndUnmarshall(c, "test", "Mounts", &mounts)
|
||||
c.Assert(mounts, checker.HasLen, 1)
|
||||
c.Assert(mounts[0].Driver, checker.Equals, volumePluginName)
|
||||
}
|
||||
|
||||
// Ensures that the daemon handles when the plugin responds to a `Get` request with a null volume and a null error.
|
||||
// Prior the daemon would panic in this scenario.
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverGetEmptyResponse(c *check.C) {
|
||||
s.d.Start(c)
|
||||
|
||||
out, err := s.d.Cmd("volume", "create", "-d", volumePluginName, "abc2", "--opt", "ninja=1")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = s.d.Cmd("volume", "inspect", "abc2")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "No such volume")
|
||||
}
|
||||
|
||||
// Ensure only cached paths are used in volume list to prevent N+1 calls to `VolumeDriver.Path`
|
||||
//
|
||||
// TODO(@cpuguy83): This test is testing internal implementation. In all the cases here, there may not even be a path
|
||||
// available because the volume is not even mounted. Consider removing this test.
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverPathCalls(c *check.C) {
|
||||
s.d.Start(c)
|
||||
c.Assert(s.ec.paths, checker.Equals, 0)
|
||||
|
||||
out, err := s.d.Cmd("volume", "create", "test", "--driver=test-external-volume-driver")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(s.ec.paths, checker.Equals, 0)
|
||||
|
||||
out, err = s.d.Cmd("volume", "ls")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(s.ec.paths, checker.Equals, 0)
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverMountID(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
|
||||
out, err := s.d.Cmd("run", "--rm", "-v", "external-volume-test:/tmp/external-volume-test", "--volume-driver", volumePluginName, "busybox:latest", "cat", "/tmp/external-volume-test/test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
}
|
||||
|
||||
// Check that VolumeDriver.Capabilities gets called, and only called once
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverCapabilities(c *check.C) {
|
||||
s.d.Start(c)
|
||||
c.Assert(s.ec.caps, checker.Equals, 0)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
out, err := s.d.Cmd("volume", "create", "-d", volumePluginName, fmt.Sprintf("test%d", i))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(s.ec.caps, checker.Equals, 1)
|
||||
out, err = s.d.Cmd("volume", "inspect", "--format={{.Scope}}", fmt.Sprintf("test%d", i))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, volume.GlobalScope)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverOutOfBandDelete(c *check.C) {
|
||||
driverName := stringid.GenerateNonCryptoID()
|
||||
p := newVolumePlugin(c, driverName)
|
||||
defer p.Close()
|
||||
|
||||
s.d.StartWithBusybox(c)
|
||||
|
||||
out, err := s.d.Cmd("volume", "create", "-d", driverName, "--name", "test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = s.d.Cmd("volume", "create", "-d", "local", "--name", "test")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "must be unique")
|
||||
|
||||
// simulate out of band volume deletion on plugin level
|
||||
delete(p.vols, "test")
|
||||
|
||||
// test re-create with same driver
|
||||
out, err = s.d.Cmd("volume", "create", "-d", driverName, "--opt", "foo=bar", "--name", "test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
out, err = s.d.Cmd("volume", "inspect", "test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
var vs []types.Volume
|
||||
err = json.Unmarshal([]byte(out), &vs)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(vs, checker.HasLen, 1)
|
||||
c.Assert(vs[0].Driver, checker.Equals, driverName)
|
||||
c.Assert(vs[0].Options, checker.NotNil)
|
||||
c.Assert(vs[0].Options["foo"], checker.Equals, "bar")
|
||||
c.Assert(vs[0].Driver, checker.Equals, driverName)
|
||||
|
||||
// simulate out of band volume deletion on plugin level
|
||||
delete(p.vols, "test")
|
||||
|
||||
// test create with different driver
|
||||
out, err = s.d.Cmd("volume", "create", "-d", "local", "--name", "test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = s.d.Cmd("volume", "inspect", "test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
vs = nil
|
||||
err = json.Unmarshal([]byte(out), &vs)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(vs, checker.HasLen, 1)
|
||||
c.Assert(vs[0].Options, checker.HasLen, 0)
|
||||
c.Assert(vs[0].Driver, checker.Equals, "local")
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnmountOnMountFail(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
s.d.Cmd("volume", "create", "-d", "test-external-volume-driver", "--opt=invalidOption=1", "--name=testumount")
|
||||
|
||||
out, _ := s.d.Cmd("run", "-v", "testumount:/foo", "busybox", "true")
|
||||
c.Assert(s.ec.unmounts, checker.Equals, 0, check.Commentf("%s", out))
|
||||
out, _ = s.d.Cmd("run", "-w", "/foo", "-v", "testumount:/foo", "busybox", "true")
|
||||
c.Assert(s.ec.unmounts, checker.Equals, 0, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnmountOnCp(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
s.d.Cmd("volume", "create", "-d", "test-external-volume-driver", "--name=test")
|
||||
|
||||
out, _ := s.d.Cmd("run", "-d", "--name=test", "-v", "test:/foo", "busybox", "/bin/sh", "-c", "touch /test && top")
|
||||
c.Assert(s.ec.mounts, checker.Equals, 1, check.Commentf("%s", out))
|
||||
|
||||
out, _ = s.d.Cmd("cp", "test:/test", "/tmp/test")
|
||||
c.Assert(s.ec.mounts, checker.Equals, 2, check.Commentf("%s", out))
|
||||
c.Assert(s.ec.unmounts, checker.Equals, 1, check.Commentf("%s", out))
|
||||
|
||||
out, _ = s.d.Cmd("kill", "test")
|
||||
c.Assert(s.ec.unmounts, checker.Equals, 2, check.Commentf("%s", out))
|
||||
}
|
167
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_health_test.go
generated
vendored
Normal file
167
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_health_test.go
generated
vendored
Normal file
|
@ -0,0 +1,167 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func waitForHealthStatus(c *check.C, name string, prev string, expected string) {
|
||||
prev = prev + "\n"
|
||||
expected = expected + "\n"
|
||||
for {
|
||||
out, _ := dockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name)
|
||||
if out == expected {
|
||||
return
|
||||
}
|
||||
c.Check(out, checker.Equals, prev)
|
||||
if out != prev {
|
||||
return
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func getHealth(c *check.C, name string) *types.Health {
|
||||
out, _ := dockerCmd(c, "inspect", "--format={{json .State.Health}}", name)
|
||||
var health types.Health
|
||||
err := json.Unmarshal([]byte(out), &health)
|
||||
c.Check(err, checker.Equals, nil)
|
||||
return &health
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestHealth(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows
|
||||
|
||||
existingContainers := ExistingContainerIDs(c)
|
||||
|
||||
imageName := "testhealth"
|
||||
buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox
|
||||
RUN echo OK > /status
|
||||
CMD ["/bin/sleep", "120"]
|
||||
STOPSIGNAL SIGKILL
|
||||
HEALTHCHECK --interval=1s --timeout=30s \
|
||||
CMD cat /status`))
|
||||
|
||||
// No health status before starting
|
||||
name := "test_health"
|
||||
cid, _ := dockerCmd(c, "create", "--name", name, imageName)
|
||||
out, _ := dockerCmd(c, "ps", "-a", "--format={{.ID}} {{.Status}}")
|
||||
out = RemoveOutputForExistingElements(out, existingContainers)
|
||||
c.Check(out, checker.Equals, cid[:12]+" Created\n")
|
||||
|
||||
// Inspect the options
|
||||
out, _ = dockerCmd(c, "inspect",
|
||||
"--format=timeout={{.Config.Healthcheck.Timeout}} interval={{.Config.Healthcheck.Interval}} retries={{.Config.Healthcheck.Retries}} test={{.Config.Healthcheck.Test}}", name)
|
||||
c.Check(out, checker.Equals, "timeout=30s interval=1s retries=0 test=[CMD-SHELL cat /status]\n")
|
||||
|
||||
// Start
|
||||
dockerCmd(c, "start", name)
|
||||
waitForHealthStatus(c, name, "starting", "healthy")
|
||||
|
||||
// Make it fail
|
||||
dockerCmd(c, "exec", name, "rm", "/status")
|
||||
waitForHealthStatus(c, name, "healthy", "unhealthy")
|
||||
|
||||
// Inspect the status
|
||||
out, _ = dockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name)
|
||||
c.Check(out, checker.Equals, "unhealthy\n")
|
||||
|
||||
// Make it healthy again
|
||||
dockerCmd(c, "exec", name, "touch", "/status")
|
||||
waitForHealthStatus(c, name, "unhealthy", "healthy")
|
||||
|
||||
// Remove container
|
||||
dockerCmd(c, "rm", "-f", name)
|
||||
|
||||
// Disable the check from the CLI
|
||||
dockerCmd(c, "create", "--name=noh", "--no-healthcheck", imageName)
|
||||
out, _ = dockerCmd(c, "inspect", "--format={{.Config.Healthcheck.Test}}", "noh")
|
||||
c.Check(out, checker.Equals, "[NONE]\n")
|
||||
dockerCmd(c, "rm", "noh")
|
||||
|
||||
// Disable the check with a new build
|
||||
buildImageSuccessfully(c, "no_healthcheck", build.WithDockerfile(`FROM testhealth
|
||||
HEALTHCHECK NONE`))
|
||||
|
||||
out, _ = dockerCmd(c, "inspect", "--format={{.Config.Healthcheck.Test}}", "no_healthcheck")
|
||||
c.Check(out, checker.Equals, "[NONE]\n")
|
||||
|
||||
// Enable the checks from the CLI
|
||||
_, _ = dockerCmd(c, "run", "-d", "--name=fatal_healthcheck",
|
||||
"--health-interval=1s",
|
||||
"--health-retries=3",
|
||||
"--health-cmd=cat /status",
|
||||
"no_healthcheck")
|
||||
waitForHealthStatus(c, "fatal_healthcheck", "starting", "healthy")
|
||||
health := getHealth(c, "fatal_healthcheck")
|
||||
c.Check(health.Status, checker.Equals, "healthy")
|
||||
c.Check(health.FailingStreak, checker.Equals, 0)
|
||||
last := health.Log[len(health.Log)-1]
|
||||
c.Check(last.ExitCode, checker.Equals, 0)
|
||||
c.Check(last.Output, checker.Equals, "OK\n")
|
||||
|
||||
// Fail the check
|
||||
dockerCmd(c, "exec", "fatal_healthcheck", "rm", "/status")
|
||||
waitForHealthStatus(c, "fatal_healthcheck", "healthy", "unhealthy")
|
||||
|
||||
failsStr, _ := dockerCmd(c, "inspect", "--format={{.State.Health.FailingStreak}}", "fatal_healthcheck")
|
||||
fails, err := strconv.Atoi(strings.TrimSpace(failsStr))
|
||||
c.Check(err, check.IsNil)
|
||||
c.Check(fails >= 3, checker.Equals, true)
|
||||
dockerCmd(c, "rm", "-f", "fatal_healthcheck")
|
||||
|
||||
// Check timeout
|
||||
// Note: if the interval is too small, it seems that Docker spends all its time running health
|
||||
// checks and never gets around to killing it.
|
||||
_, _ = dockerCmd(c, "run", "-d", "--name=test",
|
||||
"--health-interval=1s", "--health-cmd=sleep 5m", "--health-timeout=1s", imageName)
|
||||
waitForHealthStatus(c, "test", "starting", "unhealthy")
|
||||
health = getHealth(c, "test")
|
||||
last = health.Log[len(health.Log)-1]
|
||||
c.Check(health.Status, checker.Equals, "unhealthy")
|
||||
c.Check(last.ExitCode, checker.Equals, -1)
|
||||
c.Check(last.Output, checker.Equals, "Health check exceeded timeout (1s)")
|
||||
dockerCmd(c, "rm", "-f", "test")
|
||||
|
||||
// Check JSON-format
|
||||
buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox
|
||||
RUN echo OK > /status
|
||||
CMD ["/bin/sleep", "120"]
|
||||
STOPSIGNAL SIGKILL
|
||||
HEALTHCHECK --interval=1s --timeout=30s \
|
||||
CMD ["cat", "/my status"]`))
|
||||
out, _ = dockerCmd(c, "inspect",
|
||||
"--format={{.Config.Healthcheck.Test}}", imageName)
|
||||
c.Check(out, checker.Equals, "[CMD cat /my status]\n")
|
||||
|
||||
}
|
||||
|
||||
// GitHub #33021
|
||||
func (s *DockerSuite) TestUnsetEnvVarHealthCheck(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows
|
||||
|
||||
imageName := "testhealth"
|
||||
buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox
|
||||
HEALTHCHECK --interval=1s --timeout=5s --retries=5 CMD /bin/sh -c "sleep 1"
|
||||
ENTRYPOINT /bin/sh -c "sleep 600"`))
|
||||
|
||||
name := "env_test_health"
|
||||
// No health status before starting
|
||||
dockerCmd(c, "run", "-d", "--name", name, "-e", "FOO", imageName)
|
||||
defer func() {
|
||||
dockerCmd(c, "rm", "-f", name)
|
||||
dockerCmd(c, "rmi", imageName)
|
||||
}()
|
||||
|
||||
// Start
|
||||
dockerCmd(c, "start", name)
|
||||
waitForHealthStatus(c, name, "starting", "healthy")
|
||||
|
||||
}
|
119
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_history_test.go
generated
vendored
Normal file
119
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_history_test.go
generated
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// This is a heisen-test. Because the created timestamp of images and the behavior of
|
||||
// sort is not predictable it doesn't always fail.
|
||||
func (s *DockerSuite) TestBuildHistory(c *check.C) {
|
||||
name := "testbuildhistory"
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
|
||||
LABEL label.A="A"
|
||||
LABEL label.B="B"
|
||||
LABEL label.C="C"
|
||||
LABEL label.D="D"
|
||||
LABEL label.E="E"
|
||||
LABEL label.F="F"
|
||||
LABEL label.G="G"
|
||||
LABEL label.H="H"
|
||||
LABEL label.I="I"
|
||||
LABEL label.J="J"
|
||||
LABEL label.K="K"
|
||||
LABEL label.L="L"
|
||||
LABEL label.M="M"
|
||||
LABEL label.N="N"
|
||||
LABEL label.O="O"
|
||||
LABEL label.P="P"
|
||||
LABEL label.Q="Q"
|
||||
LABEL label.R="R"
|
||||
LABEL label.S="S"
|
||||
LABEL label.T="T"
|
||||
LABEL label.U="U"
|
||||
LABEL label.V="V"
|
||||
LABEL label.W="W"
|
||||
LABEL label.X="X"
|
||||
LABEL label.Y="Y"
|
||||
LABEL label.Z="Z"`))
|
||||
|
||||
out, _ := dockerCmd(c, "history", name)
|
||||
actualValues := strings.Split(out, "\n")[1:27]
|
||||
expectedValues := [26]string{"Z", "Y", "X", "W", "V", "U", "T", "S", "R", "Q", "P", "O", "N", "M", "L", "K", "J", "I", "H", "G", "F", "E", "D", "C", "B", "A"}
|
||||
|
||||
for i := 0; i < 26; i++ {
|
||||
echoValue := fmt.Sprintf("LABEL label.%s=%s", expectedValues[i], expectedValues[i])
|
||||
actualValue := actualValues[i]
|
||||
c.Assert(actualValue, checker.Contains, echoValue)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestHistoryExistentImage(c *check.C) {
|
||||
dockerCmd(c, "history", "busybox")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestHistoryNonExistentImage(c *check.C) {
|
||||
_, _, err := dockerCmdWithError("history", "testHistoryNonExistentImage")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("history on a non-existent image should fail."))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestHistoryImageWithComment(c *check.C) {
|
||||
name := "testhistoryimagewithcomment"
|
||||
|
||||
// make an image through docker commit <container id> [ -m messages ]
|
||||
|
||||
dockerCmd(c, "run", "--name", name, "busybox", "true")
|
||||
dockerCmd(c, "wait", name)
|
||||
|
||||
comment := "This_is_a_comment"
|
||||
dockerCmd(c, "commit", "-m="+comment, name, name)
|
||||
|
||||
// test docker history <image id> to check comment messages
|
||||
|
||||
out, _ := dockerCmd(c, "history", name)
|
||||
outputTabs := strings.Fields(strings.Split(out, "\n")[1])
|
||||
actualValue := outputTabs[len(outputTabs)-1]
|
||||
c.Assert(actualValue, checker.Contains, comment)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestHistoryHumanOptionFalse(c *check.C) {
|
||||
out, _ := dockerCmd(c, "history", "--human=false", "busybox")
|
||||
lines := strings.Split(out, "\n")
|
||||
sizeColumnRegex, _ := regexp.Compile("SIZE +")
|
||||
indices := sizeColumnRegex.FindStringIndex(lines[0])
|
||||
startIndex := indices[0]
|
||||
endIndex := indices[1]
|
||||
for i := 1; i < len(lines)-1; i++ {
|
||||
if endIndex > len(lines[i]) {
|
||||
endIndex = len(lines[i])
|
||||
}
|
||||
sizeString := lines[i][startIndex:endIndex]
|
||||
|
||||
_, err := strconv.Atoi(strings.TrimSpace(sizeString))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("The size '%s' was not an Integer", sizeString))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestHistoryHumanOptionTrue(c *check.C) {
|
||||
out, _ := dockerCmd(c, "history", "--human=true", "busybox")
|
||||
lines := strings.Split(out, "\n")
|
||||
sizeColumnRegex, _ := regexp.Compile("SIZE +")
|
||||
humanSizeRegexRaw := "\\d+.*B" // Matches human sizes like 10 MB, 3.2 KB, etc
|
||||
indices := sizeColumnRegex.FindStringIndex(lines[0])
|
||||
startIndex := indices[0]
|
||||
endIndex := indices[1]
|
||||
for i := 1; i < len(lines)-1; i++ {
|
||||
if endIndex > len(lines[i]) {
|
||||
endIndex = len(lines[i])
|
||||
}
|
||||
sizeString := lines[i][startIndex:endIndex]
|
||||
c.Assert(strings.TrimSpace(sizeString), checker.Matches, humanSizeRegexRaw, check.Commentf("The size '%s' was not in human format", sizeString))
|
||||
}
|
||||
}
|
366
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_images_test.go
generated
vendored
Normal file
366
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_images_test.go
generated
vendored
Normal file
|
@ -0,0 +1,366 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestImagesEnsureImageIsListed(c *check.C) {
|
||||
imagesOut, _ := dockerCmd(c, "images")
|
||||
c.Assert(imagesOut, checker.Contains, "busybox")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImagesEnsureImageWithTagIsListed(c *check.C) {
|
||||
name := "imagewithtag"
|
||||
dockerCmd(c, "tag", "busybox", name+":v1")
|
||||
dockerCmd(c, "tag", "busybox", name+":v1v1")
|
||||
dockerCmd(c, "tag", "busybox", name+":v2")
|
||||
|
||||
imagesOut, _ := dockerCmd(c, "images", name+":v1")
|
||||
c.Assert(imagesOut, checker.Contains, name)
|
||||
c.Assert(imagesOut, checker.Contains, "v1")
|
||||
c.Assert(imagesOut, checker.Not(checker.Contains), "v2")
|
||||
c.Assert(imagesOut, checker.Not(checker.Contains), "v1v1")
|
||||
|
||||
imagesOut, _ = dockerCmd(c, "images", name)
|
||||
c.Assert(imagesOut, checker.Contains, name)
|
||||
c.Assert(imagesOut, checker.Contains, "v1")
|
||||
c.Assert(imagesOut, checker.Contains, "v1v1")
|
||||
c.Assert(imagesOut, checker.Contains, "v2")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImagesEnsureImageWithBadTagIsNotListed(c *check.C) {
|
||||
imagesOut, _ := dockerCmd(c, "images", "busybox:nonexistent")
|
||||
c.Assert(imagesOut, checker.Not(checker.Contains), "busybox")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImagesOrderedByCreationDate(c *check.C) {
|
||||
buildImageSuccessfully(c, "order:test_a", build.WithDockerfile(`FROM busybox
|
||||
MAINTAINER dockerio1`))
|
||||
id1 := getIDByName(c, "order:test_a")
|
||||
time.Sleep(1 * time.Second)
|
||||
buildImageSuccessfully(c, "order:test_c", build.WithDockerfile(`FROM busybox
|
||||
MAINTAINER dockerio2`))
|
||||
id2 := getIDByName(c, "order:test_c")
|
||||
time.Sleep(1 * time.Second)
|
||||
buildImageSuccessfully(c, "order:test_b", build.WithDockerfile(`FROM busybox
|
||||
MAINTAINER dockerio3`))
|
||||
id3 := getIDByName(c, "order:test_b")
|
||||
|
||||
out, _ := dockerCmd(c, "images", "-q", "--no-trunc")
|
||||
imgs := strings.Split(out, "\n")
|
||||
c.Assert(imgs[0], checker.Equals, id3, check.Commentf("First image must be %s, got %s", id3, imgs[0]))
|
||||
c.Assert(imgs[1], checker.Equals, id2, check.Commentf("First image must be %s, got %s", id2, imgs[1]))
|
||||
c.Assert(imgs[2], checker.Equals, id1, check.Commentf("First image must be %s, got %s", id1, imgs[2]))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImagesErrorWithInvalidFilterNameTest(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("images", "-f", "FOO=123")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "Invalid filter")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImagesFilterLabelMatch(c *check.C) {
|
||||
imageName1 := "images_filter_test1"
|
||||
imageName2 := "images_filter_test2"
|
||||
imageName3 := "images_filter_test3"
|
||||
buildImageSuccessfully(c, imageName1, build.WithDockerfile(`FROM busybox
|
||||
LABEL match me`))
|
||||
image1ID := getIDByName(c, imageName1)
|
||||
|
||||
buildImageSuccessfully(c, imageName2, build.WithDockerfile(`FROM busybox
|
||||
LABEL match="me too"`))
|
||||
image2ID := getIDByName(c, imageName2)
|
||||
|
||||
buildImageSuccessfully(c, imageName3, build.WithDockerfile(`FROM busybox
|
||||
LABEL nomatch me`))
|
||||
image3ID := getIDByName(c, imageName3)
|
||||
|
||||
out, _ := dockerCmd(c, "images", "--no-trunc", "-q", "-f", "label=match")
|
||||
out = strings.TrimSpace(out)
|
||||
c.Assert(out, check.Matches, fmt.Sprintf("[\\s\\w:]*%s[\\s\\w:]*", image1ID))
|
||||
c.Assert(out, check.Matches, fmt.Sprintf("[\\s\\w:]*%s[\\s\\w:]*", image2ID))
|
||||
c.Assert(out, check.Not(check.Matches), fmt.Sprintf("[\\s\\w:]*%s[\\s\\w:]*", image3ID))
|
||||
|
||||
out, _ = dockerCmd(c, "images", "--no-trunc", "-q", "-f", "label=match=me too")
|
||||
out = strings.TrimSpace(out)
|
||||
c.Assert(out, check.Equals, image2ID)
|
||||
}
|
||||
|
||||
// Regression : #15659
|
||||
func (s *DockerSuite) TestCommitWithFilterLabel(c *check.C) {
|
||||
// Create a container
|
||||
dockerCmd(c, "run", "--name", "bar", "busybox", "/bin/sh")
|
||||
// Commit with labels "using changes"
|
||||
out, _ := dockerCmd(c, "commit", "-c", "LABEL foo.version=1.0.0-1", "-c", "LABEL foo.name=bar", "-c", "LABEL foo.author=starlord", "bar", "bar:1.0.0-1")
|
||||
imageID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "images", "--no-trunc", "-q", "-f", "label=foo.version=1.0.0-1")
|
||||
out = strings.TrimSpace(out)
|
||||
c.Assert(out, check.Equals, imageID)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImagesFilterSinceAndBefore(c *check.C) {
|
||||
buildImageSuccessfully(c, "image:1", build.WithDockerfile(`FROM `+minimalBaseImage()+`
|
||||
LABEL number=1`))
|
||||
imageID1 := getIDByName(c, "image:1")
|
||||
buildImageSuccessfully(c, "image:2", build.WithDockerfile(`FROM `+minimalBaseImage()+`
|
||||
LABEL number=2`))
|
||||
imageID2 := getIDByName(c, "image:2")
|
||||
buildImageSuccessfully(c, "image:3", build.WithDockerfile(`FROM `+minimalBaseImage()+`
|
||||
LABEL number=3`))
|
||||
imageID3 := getIDByName(c, "image:3")
|
||||
|
||||
expected := []string{imageID3, imageID2}
|
||||
|
||||
out, _ := dockerCmd(c, "images", "-f", "since=image:1", "image")
|
||||
c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out))
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-f", "since="+imageID1, "image")
|
||||
c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out))
|
||||
|
||||
expected = []string{imageID3}
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-f", "since=image:2", "image")
|
||||
c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out))
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-f", "since="+imageID2, "image")
|
||||
c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out))
|
||||
|
||||
expected = []string{imageID2, imageID1}
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-f", "before=image:3", "image")
|
||||
c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out))
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-f", "before="+imageID3, "image")
|
||||
c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out))
|
||||
|
||||
expected = []string{imageID1}
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-f", "before=image:2", "image")
|
||||
c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out))
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-f", "before="+imageID2, "image")
|
||||
c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out))
|
||||
}
|
||||
|
||||
func assertImageList(out string, expected []string) bool {
|
||||
lines := strings.Split(strings.Trim(out, "\n "), "\n")
|
||||
|
||||
if len(lines)-1 != len(expected) {
|
||||
return false
|
||||
}
|
||||
|
||||
imageIDIndex := strings.Index(lines[0], "IMAGE ID")
|
||||
for i := 0; i < len(expected); i++ {
|
||||
imageID := lines[i+1][imageIDIndex : imageIDIndex+12]
|
||||
found := false
|
||||
for _, e := range expected {
|
||||
if imageID == e[7:19] {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) should be a unit test on `docker image ls`
|
||||
func (s *DockerSuite) TestImagesFilterSpaceTrimCase(c *check.C) {
|
||||
imageName := "images_filter_test"
|
||||
// Build a image and fail to build so that we have dangling images ?
|
||||
buildImage(imageName, build.WithDockerfile(`FROM busybox
|
||||
RUN touch /test/foo
|
||||
RUN touch /test/bar
|
||||
RUN touch /test/baz`)).Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
})
|
||||
|
||||
filters := []string{
|
||||
"dangling=true",
|
||||
"Dangling=true",
|
||||
" dangling=true",
|
||||
"dangling=true ",
|
||||
"dangling = true",
|
||||
}
|
||||
|
||||
imageListings := make([][]string, 5, 5)
|
||||
for idx, filter := range filters {
|
||||
out, _ := dockerCmd(c, "images", "-q", "-f", filter)
|
||||
listing := strings.Split(out, "\n")
|
||||
sort.Strings(listing)
|
||||
imageListings[idx] = listing
|
||||
}
|
||||
|
||||
for idx, listing := range imageListings {
|
||||
if idx < 4 && !reflect.DeepEqual(listing, imageListings[idx+1]) {
|
||||
for idx, errListing := range imageListings {
|
||||
fmt.Printf("out %d\n", idx)
|
||||
for _, image := range errListing {
|
||||
fmt.Print(image)
|
||||
}
|
||||
fmt.Print("")
|
||||
}
|
||||
c.Fatalf("All output must be the same")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImagesEnsureDanglingImageOnlyListedOnce(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// create container 1
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
containerID1 := strings.TrimSpace(out)
|
||||
|
||||
// tag as foobox
|
||||
out, _ = dockerCmd(c, "commit", containerID1, "foobox")
|
||||
imageID := stringid.TruncateID(strings.TrimSpace(out))
|
||||
|
||||
// overwrite the tag, making the previous image dangling
|
||||
dockerCmd(c, "tag", "busybox", "foobox")
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-q", "-f", "dangling=true")
|
||||
// Expect one dangling image
|
||||
c.Assert(strings.Count(out, imageID), checker.Equals, 1)
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-q", "-f", "dangling=false")
|
||||
//dangling=false would not include dangling images
|
||||
c.Assert(out, checker.Not(checker.Contains), imageID)
|
||||
|
||||
out, _ = dockerCmd(c, "images")
|
||||
//docker images still include dangling images
|
||||
c.Assert(out, checker.Contains, imageID)
|
||||
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) should be a unit test for `docker image ls`
|
||||
func (s *DockerSuite) TestImagesWithIncorrectFilter(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("images", "-f", "dangling=invalid")
|
||||
c.Assert(err, check.NotNil)
|
||||
c.Assert(out, checker.Contains, "Invalid filter")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImagesEnsureOnlyHeadsImagesShown(c *check.C) {
|
||||
dockerfile := `
|
||||
FROM busybox
|
||||
MAINTAINER docker
|
||||
ENV foo bar`
|
||||
name := "scratch-image"
|
||||
result := buildImage(name, build.WithDockerfile(dockerfile))
|
||||
result.Assert(c, icmd.Success)
|
||||
id := getIDByName(c, name)
|
||||
|
||||
// this is just the output of docker build
|
||||
// we're interested in getting the image id of the MAINTAINER instruction
|
||||
// and that's located at output, line 5, from 7 to end
|
||||
split := strings.Split(result.Combined(), "\n")
|
||||
intermediate := strings.TrimSpace(split[5][7:])
|
||||
|
||||
out, _ := dockerCmd(c, "images")
|
||||
// images shouldn't show non-heads images
|
||||
c.Assert(out, checker.Not(checker.Contains), intermediate)
|
||||
// images should contain final built images
|
||||
c.Assert(out, checker.Contains, stringid.TruncateID(id))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImagesEnsureImagesFromScratchShown(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux) // Windows does not support FROM scratch
|
||||
dockerfile := `
|
||||
FROM scratch
|
||||
MAINTAINER docker`
|
||||
|
||||
name := "scratch-image"
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(dockerfile))
|
||||
id := getIDByName(c, name)
|
||||
|
||||
out, _ := dockerCmd(c, "images")
|
||||
// images should contain images built from scratch
|
||||
c.Assert(out, checker.Contains, stringid.TruncateID(id))
|
||||
}
|
||||
|
||||
// For W2W - equivalent to TestImagesEnsureImagesFromScratchShown but Windows
|
||||
// doesn't support from scratch
|
||||
func (s *DockerSuite) TestImagesEnsureImagesFromBusyboxShown(c *check.C) {
|
||||
dockerfile := `
|
||||
FROM busybox
|
||||
MAINTAINER docker`
|
||||
name := "busybox-image"
|
||||
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(dockerfile))
|
||||
id := getIDByName(c, name)
|
||||
|
||||
out, _ := dockerCmd(c, "images")
|
||||
// images should contain images built from busybox
|
||||
c.Assert(out, checker.Contains, stringid.TruncateID(id))
|
||||
}
|
||||
|
||||
// #18181
|
||||
func (s *DockerSuite) TestImagesFilterNameWithPort(c *check.C) {
|
||||
tag := "a.b.c.d:5000/hello"
|
||||
dockerCmd(c, "tag", "busybox", tag)
|
||||
out, _ := dockerCmd(c, "images", tag)
|
||||
c.Assert(out, checker.Contains, tag)
|
||||
|
||||
out, _ = dockerCmd(c, "images", tag+":latest")
|
||||
c.Assert(out, checker.Contains, tag)
|
||||
|
||||
out, _ = dockerCmd(c, "images", tag+":no-such-tag")
|
||||
c.Assert(out, checker.Not(checker.Contains), tag)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImagesFormat(c *check.C) {
|
||||
// testRequires(c, DaemonIsLinux)
|
||||
tag := "myimage"
|
||||
dockerCmd(c, "tag", "busybox", tag+":v1")
|
||||
dockerCmd(c, "tag", "busybox", tag+":v2")
|
||||
|
||||
out, _ := dockerCmd(c, "images", "--format", "{{.Repository}}", tag)
|
||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
|
||||
expected := []string{"myimage", "myimage"}
|
||||
var names []string
|
||||
names = append(names, lines...)
|
||||
c.Assert(names, checker.DeepEquals, expected, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
|
||||
}
|
||||
|
||||
// ImagesDefaultFormatAndQuiet
|
||||
func (s *DockerSuite) TestImagesFormatDefaultFormat(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// create container 1
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
containerID1 := strings.TrimSpace(out)
|
||||
|
||||
// tag as foobox
|
||||
out, _ = dockerCmd(c, "commit", containerID1, "myimage")
|
||||
imageID := stringid.TruncateID(strings.TrimSpace(out))
|
||||
|
||||
config := `{
|
||||
"imagesFormat": "{{ .ID }} default"
|
||||
}`
|
||||
d, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "--config", d, "images", "-q", "myimage")
|
||||
c.Assert(out, checker.Equals, imageID+"\n", check.Commentf("Expected to print only the image id, got %v\n", out))
|
||||
}
|
142
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_import_test.go
generated
vendored
Normal file
142
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_import_test.go
generated
vendored
Normal file
|
@ -0,0 +1,142 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"compress/gzip"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestImportDisplay(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "export", cleanedContainerID),
|
||||
exec.Command(dockerBinary, "import", "-"),
|
||||
)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(out, checker.Count, "\n", 1, check.Commentf("display is expected 1 '\\n' but didn't"))
|
||||
|
||||
image := strings.TrimSpace(out)
|
||||
out, _ = dockerCmd(c, "run", "--rm", image, "true")
|
||||
c.Assert(out, checker.Equals, "", check.Commentf("command output should've been nothing."))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImportBadURL(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("import", "http://nourl/bad")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("import was supposed to fail but didn't"))
|
||||
// Depending on your system you can get either of these errors
|
||||
if !strings.Contains(out, "dial tcp") &&
|
||||
!strings.Contains(out, "ApplyLayer exit status 1 stdout: stderr: archive/tar: invalid tar header") &&
|
||||
!strings.Contains(out, "Error processing tar file") {
|
||||
c.Fatalf("expected an error msg but didn't get one.\nErr: %v\nOut: %v", err, out)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImportFile(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "--name", "test-import", "busybox", "true")
|
||||
|
||||
temporaryFile, err := ioutil.TempFile("", "exportImportTest")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to create temporary file"))
|
||||
defer os.Remove(temporaryFile.Name())
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "export", "test-import"},
|
||||
Stdout: bufio.NewWriter(temporaryFile),
|
||||
}).Assert(c, icmd.Success)
|
||||
|
||||
out, _ := dockerCmd(c, "import", temporaryFile.Name())
|
||||
c.Assert(out, checker.Count, "\n", 1, check.Commentf("display is expected 1 '\\n' but didn't"))
|
||||
image := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "run", "--rm", image, "true")
|
||||
c.Assert(out, checker.Equals, "", check.Commentf("command output should've been nothing."))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImportGzipped(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "--name", "test-import", "busybox", "true")
|
||||
|
||||
temporaryFile, err := ioutil.TempFile("", "exportImportTest")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to create temporary file"))
|
||||
defer os.Remove(temporaryFile.Name())
|
||||
|
||||
w := gzip.NewWriter(temporaryFile)
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "export", "test-import"},
|
||||
Stdout: w,
|
||||
}).Assert(c, icmd.Success)
|
||||
c.Assert(w.Close(), checker.IsNil, check.Commentf("failed to close gzip writer"))
|
||||
temporaryFile.Close()
|
||||
out, _ := dockerCmd(c, "import", temporaryFile.Name())
|
||||
c.Assert(out, checker.Count, "\n", 1, check.Commentf("display is expected 1 '\\n' but didn't"))
|
||||
image := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "run", "--rm", image, "true")
|
||||
c.Assert(out, checker.Equals, "", check.Commentf("command output should've been nothing."))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImportFileWithMessage(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "--name", "test-import", "busybox", "true")
|
||||
|
||||
temporaryFile, err := ioutil.TempFile("", "exportImportTest")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to create temporary file"))
|
||||
defer os.Remove(temporaryFile.Name())
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "export", "test-import"},
|
||||
Stdout: bufio.NewWriter(temporaryFile),
|
||||
}).Assert(c, icmd.Success)
|
||||
|
||||
message := "Testing commit message"
|
||||
out, _ := dockerCmd(c, "import", "-m", message, temporaryFile.Name())
|
||||
c.Assert(out, checker.Count, "\n", 1, check.Commentf("display is expected 1 '\\n' but didn't"))
|
||||
image := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "history", image)
|
||||
split := strings.Split(out, "\n")
|
||||
|
||||
c.Assert(split, checker.HasLen, 3, check.Commentf("expected 3 lines from image history"))
|
||||
r := regexp.MustCompile("[\\s]{2,}")
|
||||
split = r.Split(split[1], -1)
|
||||
|
||||
c.Assert(message, checker.Equals, split[3], check.Commentf("didn't get expected value in commit message"))
|
||||
|
||||
out, _ = dockerCmd(c, "run", "--rm", image, "true")
|
||||
c.Assert(out, checker.Equals, "", check.Commentf("command output should've been nothing"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImportFileNonExistentFile(c *check.C) {
|
||||
_, _, err := dockerCmdWithError("import", "example.com/myImage.tar")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("import non-existing file must failed"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestImportWithQuotedChanges(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
cli.DockerCmd(c, "run", "--name", "test-import", "busybox", "true")
|
||||
|
||||
temporaryFile, err := ioutil.TempFile("", "exportImportTest")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to create temporary file"))
|
||||
defer os.Remove(temporaryFile.Name())
|
||||
|
||||
cli.Docker(cli.Args("export", "test-import"), cli.WithStdout(bufio.NewWriter(temporaryFile))).Assert(c, icmd.Success)
|
||||
|
||||
result := cli.DockerCmd(c, "import", "-c", `ENTRYPOINT ["/bin/sh", "-c"]`, temporaryFile.Name())
|
||||
image := strings.TrimSpace(result.Stdout())
|
||||
|
||||
result = cli.DockerCmd(c, "run", "--rm", image, "true")
|
||||
result.Assert(c, icmd.Expected{Out: icmd.None})
|
||||
}
|
238
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_info_test.go
generated
vendored
Normal file
238
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_info_test.go
generated
vendored
Normal file
|
@ -0,0 +1,238 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
testdaemon "github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// ensure docker info succeeds
|
||||
func (s *DockerSuite) TestInfoEnsureSucceeds(c *check.C) {
|
||||
out, _ := dockerCmd(c, "info")
|
||||
|
||||
// always shown fields
|
||||
stringsToCheck := []string{
|
||||
"ID:",
|
||||
"Containers:",
|
||||
" Running:",
|
||||
" Paused:",
|
||||
" Stopped:",
|
||||
"Images:",
|
||||
"OSType:",
|
||||
"Architecture:",
|
||||
"Logging Driver:",
|
||||
"Operating System:",
|
||||
"CPUs:",
|
||||
"Total Memory:",
|
||||
"Kernel Version:",
|
||||
"Storage Driver:",
|
||||
"Volume:",
|
||||
"Network:",
|
||||
"Live Restore Enabled:",
|
||||
}
|
||||
|
||||
if testEnv.OSType == "linux" {
|
||||
stringsToCheck = append(stringsToCheck, "Init Binary:", "Security Options:", "containerd version:", "runc version:", "init version:")
|
||||
}
|
||||
|
||||
if DaemonIsLinux() {
|
||||
stringsToCheck = append(stringsToCheck, "Runtimes:", "Default Runtime: runc")
|
||||
}
|
||||
|
||||
if testEnv.DaemonInfo.ExperimentalBuild {
|
||||
stringsToCheck = append(stringsToCheck, "Experimental: true")
|
||||
} else {
|
||||
stringsToCheck = append(stringsToCheck, "Experimental: false")
|
||||
}
|
||||
|
||||
for _, linePrefix := range stringsToCheck {
|
||||
c.Assert(out, checker.Contains, linePrefix, check.Commentf("couldn't find string %v in output", linePrefix))
|
||||
}
|
||||
}
|
||||
|
||||
// TestInfoFormat tests `docker info --format`
|
||||
func (s *DockerSuite) TestInfoFormat(c *check.C) {
|
||||
out, status := dockerCmd(c, "info", "--format", "{{json .}}")
|
||||
c.Assert(status, checker.Equals, 0)
|
||||
var m map[string]interface{}
|
||||
err := json.Unmarshal([]byte(out), &m)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, _, err = dockerCmdWithError("info", "--format", "{{.badString}}")
|
||||
c.Assert(err, checker.NotNil)
|
||||
}
|
||||
|
||||
// TestInfoDiscoveryBackend verifies that a daemon run with `--cluster-advertise` and
|
||||
// `--cluster-store` properly show the backend's endpoint in info output.
|
||||
func (s *DockerSuite) TestInfoDiscoveryBackend(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
discoveryBackend := "consul://consuladdr:consulport/some/path"
|
||||
discoveryAdvertise := "1.1.1.1:2375"
|
||||
d.Start(c, fmt.Sprintf("--cluster-store=%s", discoveryBackend), fmt.Sprintf("--cluster-advertise=%s", discoveryAdvertise))
|
||||
defer d.Stop(c)
|
||||
|
||||
out, err := d.Cmd("info")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("Cluster Store: %s\n", discoveryBackend))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("Cluster Advertise: %s\n", discoveryAdvertise))
|
||||
}
|
||||
|
||||
// TestInfoDiscoveryInvalidAdvertise verifies that a daemon run with
|
||||
// an invalid `--cluster-advertise` configuration
|
||||
func (s *DockerSuite) TestInfoDiscoveryInvalidAdvertise(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
discoveryBackend := "consul://consuladdr:consulport/some/path"
|
||||
|
||||
// --cluster-advertise with an invalid string is an error
|
||||
err := d.StartWithError(fmt.Sprintf("--cluster-store=%s", discoveryBackend), "--cluster-advertise=invalid")
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
// --cluster-advertise without --cluster-store is also an error
|
||||
err = d.StartWithError("--cluster-advertise=1.1.1.1:2375")
|
||||
c.Assert(err, checker.NotNil)
|
||||
}
|
||||
|
||||
// TestInfoDiscoveryAdvertiseInterfaceName verifies that a daemon run with `--cluster-advertise`
|
||||
// configured with interface name properly show the advertise ip-address in info output.
|
||||
func (s *DockerSuite) TestInfoDiscoveryAdvertiseInterfaceName(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, Network, DaemonIsLinux)
|
||||
|
||||
d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
discoveryBackend := "consul://consuladdr:consulport/some/path"
|
||||
discoveryAdvertise := "eth0"
|
||||
|
||||
d.Start(c, fmt.Sprintf("--cluster-store=%s", discoveryBackend), fmt.Sprintf("--cluster-advertise=%s:2375", discoveryAdvertise))
|
||||
defer d.Stop(c)
|
||||
|
||||
iface, err := net.InterfaceByName(discoveryAdvertise)
|
||||
c.Assert(err, checker.IsNil)
|
||||
addrs, err := iface.Addrs()
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(len(addrs), checker.GreaterThan, 0)
|
||||
ip, _, err := net.ParseCIDR(addrs[0].String())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, err := d.Cmd("info")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("Cluster Store: %s\n", discoveryBackend))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("Cluster Advertise: %s:2375\n", ip.String()))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInfoDisplaysRunningContainers(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
existing := existingContainerStates(c)
|
||||
|
||||
dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
out, _ := dockerCmd(c, "info")
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("Containers: %d\n", existing["Containers"]+1))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" Running: %d\n", existing["ContainersRunning"]+1))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" Paused: %d\n", existing["ContainersPaused"]))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" Stopped: %d\n", existing["ContainersStopped"]))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInfoDisplaysPausedContainers(c *check.C) {
|
||||
testRequires(c, IsPausable)
|
||||
|
||||
existing := existingContainerStates(c)
|
||||
|
||||
out := runSleepingContainer(c, "-d")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "pause", cleanedContainerID)
|
||||
|
||||
out, _ = dockerCmd(c, "info")
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("Containers: %d\n", existing["Containers"]+1))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" Running: %d\n", existing["ContainersRunning"]))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" Paused: %d\n", existing["ContainersPaused"]+1))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" Stopped: %d\n", existing["ContainersStopped"]))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInfoDisplaysStoppedContainers(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
existing := existingContainerStates(c)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "stop", cleanedContainerID)
|
||||
|
||||
out, _ = dockerCmd(c, "info")
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("Containers: %d\n", existing["Containers"]+1))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" Running: %d\n", existing["ContainersRunning"]))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" Paused: %d\n", existing["ContainersPaused"]))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" Stopped: %d\n", existing["ContainersStopped"]+1))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInfoDebug(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
d.Start(c, "--debug")
|
||||
defer d.Stop(c)
|
||||
|
||||
out, err := d.Cmd("--debug", "info")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, "Debug Mode (client): true\n")
|
||||
c.Assert(out, checker.Contains, "Debug Mode (server): true\n")
|
||||
c.Assert(out, checker.Contains, "File Descriptors")
|
||||
c.Assert(out, checker.Contains, "Goroutines")
|
||||
c.Assert(out, checker.Contains, "System Time")
|
||||
c.Assert(out, checker.Contains, "EventsListeners")
|
||||
c.Assert(out, checker.Contains, "Docker Root Dir")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInsecureRegistries(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
registryCIDR := "192.168.1.0/24"
|
||||
registryHost := "insecurehost.com:5000"
|
||||
|
||||
d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
d.Start(c, "--insecure-registry="+registryCIDR, "--insecure-registry="+registryHost)
|
||||
defer d.Stop(c)
|
||||
|
||||
out, err := d.Cmd("info")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, "Insecure Registries:\n")
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" %s\n", registryHost))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" %s\n", registryCIDR))
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestRegistryMirrors(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
registryMirror1 := "https://192.168.1.2"
|
||||
registryMirror2 := "http://registry.mirror.com:5000"
|
||||
|
||||
s.d.Start(c, "--registry-mirror="+registryMirror1, "--registry-mirror="+registryMirror2)
|
||||
|
||||
out, err := s.d.Cmd("info")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, "Registry Mirrors:\n")
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" %s", registryMirror1))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf(" %s", registryMirror2))
|
||||
}
|
||||
|
||||
func existingContainerStates(c *check.C) map[string]int {
|
||||
out, _ := dockerCmd(c, "info", "--format", "{{json .}}")
|
||||
var m map[string]interface{}
|
||||
err := json.Unmarshal([]byte(out), &m)
|
||||
c.Assert(err, checker.IsNil)
|
||||
res := map[string]int{}
|
||||
res["Containers"] = int(m["Containers"].(float64))
|
||||
res["ContainersRunning"] = int(m["ContainersRunning"].(float64))
|
||||
res["ContainersPaused"] = int(m["ContainersPaused"].(float64))
|
||||
res["ContainersStopped"] = int(m["ContainersStopped"].(float64))
|
||||
return res
|
||||
}
|
15
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_info_unix_test.go
generated
vendored
Normal file
15
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_info_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestInfoSecurityOptions(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, seccompEnabled, Apparmor, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "info")
|
||||
c.Assert(out, checker.Contains, "Security Options:\n apparmor\n seccomp\n Profile: default\n")
|
||||
}
|
460
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_inspect_test.go
generated
vendored
Normal file
460
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_inspect_test.go
generated
vendored
Normal file
|
@ -0,0 +1,460 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func checkValidGraphDriver(c *check.C, name string) {
|
||||
if name != "devicemapper" && name != "overlay" && name != "vfs" && name != "zfs" && name != "btrfs" && name != "aufs" {
|
||||
c.Fatalf("%v is not a valid graph driver name", name)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectImage(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
imageTest := "emptyfs"
|
||||
// It is important that this ID remain stable. If a code change causes
|
||||
// it to be different, this is equivalent to a cache bust when pulling
|
||||
// a legacy-format manifest. If the check at the end of this function
|
||||
// fails, fix the difference in the image serialization instead of
|
||||
// updating this hash.
|
||||
imageTestID := "sha256:11f64303f0f7ffdc71f001788132bca5346831939a956e3e975c93267d89a16d"
|
||||
id := inspectField(c, imageTest, "Id")
|
||||
|
||||
c.Assert(id, checker.Equals, imageTestID)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectInt64(c *check.C) {
|
||||
dockerCmd(c, "run", "-d", "-m=300M", "--name", "inspectTest", "busybox", "true")
|
||||
inspectOut := inspectField(c, "inspectTest", "HostConfig.Memory")
|
||||
c.Assert(inspectOut, checker.Equals, "314572800")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectDefault(c *check.C) {
|
||||
//Both the container and image are named busybox. docker inspect will fetch the container JSON.
|
||||
//If the container JSON is not available, it will go for the image JSON.
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--name=busybox", "-d", "busybox", "true")
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
inspectOut := inspectField(c, "busybox", "Id")
|
||||
c.Assert(strings.TrimSpace(inspectOut), checker.Equals, containerID)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectStatus(c *check.C) {
|
||||
out := runSleepingContainer(c, "-d")
|
||||
out = strings.TrimSpace(out)
|
||||
|
||||
inspectOut := inspectField(c, out, "State.Status")
|
||||
c.Assert(inspectOut, checker.Equals, "running")
|
||||
|
||||
// Windows does not support pause/unpause on Windows Server Containers.
|
||||
// (RS1 does for Hyper-V Containers, but production CI is not setup for that)
|
||||
if testEnv.OSType != "windows" {
|
||||
dockerCmd(c, "pause", out)
|
||||
inspectOut = inspectField(c, out, "State.Status")
|
||||
c.Assert(inspectOut, checker.Equals, "paused")
|
||||
|
||||
dockerCmd(c, "unpause", out)
|
||||
inspectOut = inspectField(c, out, "State.Status")
|
||||
c.Assert(inspectOut, checker.Equals, "running")
|
||||
}
|
||||
|
||||
dockerCmd(c, "stop", out)
|
||||
inspectOut = inspectField(c, out, "State.Status")
|
||||
c.Assert(inspectOut, checker.Equals, "exited")
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectTypeFlagContainer(c *check.C) {
|
||||
//Both the container and image are named busybox. docker inspect will fetch container
|
||||
//JSON State.Running field. If the field is true, it's a container.
|
||||
runSleepingContainer(c, "--name=busybox", "-d")
|
||||
|
||||
formatStr := "--format={{.State.Running}}"
|
||||
out, _ := dockerCmd(c, "inspect", "--type=container", formatStr, "busybox")
|
||||
c.Assert(out, checker.Equals, "true\n") // not a container JSON
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectTypeFlagWithNoContainer(c *check.C) {
|
||||
//Run this test on an image named busybox. docker inspect will try to fetch container
|
||||
//JSON. Since there is no container named busybox and --type=container, docker inspect will
|
||||
//not try to get the image JSON. It will throw an error.
|
||||
|
||||
dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
|
||||
_, _, err := dockerCmdWithError("inspect", "--type=container", "busybox")
|
||||
// docker inspect should fail, as there is no container named busybox
|
||||
c.Assert(err, checker.NotNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectTypeFlagWithImage(c *check.C) {
|
||||
//Both the container and image are named busybox. docker inspect will fetch image
|
||||
//JSON as --type=image. if there is no image with name busybox, docker inspect
|
||||
//will throw an error.
|
||||
|
||||
dockerCmd(c, "run", "--name=busybox", "-d", "busybox", "true")
|
||||
|
||||
out, _ := dockerCmd(c, "inspect", "--type=image", "busybox")
|
||||
c.Assert(out, checker.Not(checker.Contains), "State") // not an image JSON
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectTypeFlagWithInvalidValue(c *check.C) {
|
||||
//Both the container and image are named busybox. docker inspect will fail
|
||||
//as --type=foobar is not a valid value for the flag.
|
||||
|
||||
dockerCmd(c, "run", "--name=busybox", "-d", "busybox", "true")
|
||||
|
||||
out, exitCode, err := dockerCmdWithError("inspect", "--type=foobar", "busybox")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("%s", exitCode))
|
||||
c.Assert(exitCode, checker.Equals, 1, check.Commentf("%s", err))
|
||||
c.Assert(out, checker.Contains, "not a valid value for --type")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectImageFilterInt(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
imageTest := "emptyfs"
|
||||
out := inspectField(c, imageTest, "Size")
|
||||
|
||||
size, err := strconv.Atoi(out)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to inspect size of the image: %s, %v", out, err))
|
||||
|
||||
//now see if the size turns out to be the same
|
||||
formatStr := fmt.Sprintf("--format={{eq .Size %d}}", size)
|
||||
out, _ = dockerCmd(c, "inspect", formatStr, imageTest)
|
||||
result, err := strconv.ParseBool(strings.TrimSuffix(out, "\n"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(result, checker.Equals, true)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectContainerFilterInt(c *check.C) {
|
||||
result := icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "run", "-i", "-a", "stdin", "busybox", "cat"},
|
||||
Stdin: strings.NewReader("blahblah"),
|
||||
})
|
||||
result.Assert(c, icmd.Success)
|
||||
out := result.Stdout()
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
out = inspectField(c, id, "State.ExitCode")
|
||||
|
||||
exitCode, err := strconv.Atoi(out)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to inspect exitcode of the container: %s, %v", out, err))
|
||||
|
||||
//now get the exit code to verify
|
||||
formatStr := fmt.Sprintf("--format={{eq .State.ExitCode %d}}", exitCode)
|
||||
out, _ = dockerCmd(c, "inspect", formatStr, id)
|
||||
inspectResult, err := strconv.ParseBool(strings.TrimSuffix(out, "\n"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(inspectResult, checker.Equals, true)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectImageGraphDriver(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, Devicemapper)
|
||||
imageTest := "emptyfs"
|
||||
name := inspectField(c, imageTest, "GraphDriver.Name")
|
||||
|
||||
checkValidGraphDriver(c, name)
|
||||
|
||||
deviceID := inspectField(c, imageTest, "GraphDriver.Data.DeviceId")
|
||||
|
||||
_, err := strconv.Atoi(deviceID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to inspect DeviceId of the image: %s, %v", deviceID, err))
|
||||
|
||||
deviceSize := inspectField(c, imageTest, "GraphDriver.Data.DeviceSize")
|
||||
|
||||
_, err = strconv.ParseUint(deviceSize, 10, 64)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to inspect DeviceSize of the image: %s, %v", deviceSize, err))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectContainerGraphDriver(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, Devicemapper)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
out = strings.TrimSpace(out)
|
||||
|
||||
name := inspectField(c, out, "GraphDriver.Name")
|
||||
|
||||
checkValidGraphDriver(c, name)
|
||||
|
||||
imageDeviceID := inspectField(c, "busybox", "GraphDriver.Data.DeviceId")
|
||||
|
||||
deviceID := inspectField(c, out, "GraphDriver.Data.DeviceId")
|
||||
|
||||
c.Assert(imageDeviceID, checker.Not(checker.Equals), deviceID)
|
||||
|
||||
_, err := strconv.Atoi(deviceID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to inspect DeviceId of the image: %s, %v", deviceID, err))
|
||||
|
||||
deviceSize := inspectField(c, out, "GraphDriver.Data.DeviceSize")
|
||||
|
||||
_, err = strconv.ParseUint(deviceSize, 10, 64)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to inspect DeviceSize of the image: %s, %v", deviceSize, err))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectBindMountPoint(c *check.C) {
|
||||
modifier := ",z"
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
if testEnv.OSType == "windows" {
|
||||
modifier = ""
|
||||
// Linux creates the host directory if it doesn't exist. Windows does not.
|
||||
os.Mkdir(`c:\data`, os.ModeDir)
|
||||
}
|
||||
|
||||
dockerCmd(c, "run", "-d", "--name", "test", "-v", prefix+slash+"data:"+prefix+slash+"data:ro"+modifier, "busybox", "cat")
|
||||
|
||||
vol := inspectFieldJSON(c, "test", "Mounts")
|
||||
|
||||
var mp []types.MountPoint
|
||||
err := json.Unmarshal([]byte(vol), &mp)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// check that there is only one mountpoint
|
||||
c.Assert(mp, check.HasLen, 1)
|
||||
|
||||
m := mp[0]
|
||||
|
||||
c.Assert(m.Name, checker.Equals, "")
|
||||
c.Assert(m.Driver, checker.Equals, "")
|
||||
c.Assert(m.Source, checker.Equals, prefix+slash+"data")
|
||||
c.Assert(m.Destination, checker.Equals, prefix+slash+"data")
|
||||
if testEnv.OSType != "windows" { // Windows does not set mode
|
||||
c.Assert(m.Mode, checker.Equals, "ro"+modifier)
|
||||
}
|
||||
c.Assert(m.RW, checker.Equals, false)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectNamedMountPoint(c *check.C) {
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
dockerCmd(c, "run", "-d", "--name", "test", "-v", "data:"+prefix+slash+"data", "busybox", "cat")
|
||||
|
||||
vol := inspectFieldJSON(c, "test", "Mounts")
|
||||
|
||||
var mp []types.MountPoint
|
||||
err := json.Unmarshal([]byte(vol), &mp)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// check that there is only one mountpoint
|
||||
c.Assert(mp, checker.HasLen, 1)
|
||||
|
||||
m := mp[0]
|
||||
|
||||
c.Assert(m.Name, checker.Equals, "data")
|
||||
c.Assert(m.Driver, checker.Equals, "local")
|
||||
c.Assert(m.Source, checker.Not(checker.Equals), "")
|
||||
c.Assert(m.Destination, checker.Equals, prefix+slash+"data")
|
||||
c.Assert(m.RW, checker.Equals, true)
|
||||
}
|
||||
|
||||
// #14947
|
||||
func (s *DockerSuite) TestInspectTimesAsRFC3339Nano(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
id := strings.TrimSpace(out)
|
||||
startedAt := inspectField(c, id, "State.StartedAt")
|
||||
finishedAt := inspectField(c, id, "State.FinishedAt")
|
||||
created := inspectField(c, id, "Created")
|
||||
|
||||
_, err := time.Parse(time.RFC3339Nano, startedAt)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = time.Parse(time.RFC3339Nano, finishedAt)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = time.Parse(time.RFC3339Nano, created)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
created = inspectField(c, "busybox", "Created")
|
||||
|
||||
_, err = time.Parse(time.RFC3339Nano, created)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// #15633
|
||||
func (s *DockerSuite) TestInspectLogConfigNoType(c *check.C) {
|
||||
dockerCmd(c, "create", "--name=test", "--log-opt", "max-file=42", "busybox")
|
||||
var logConfig container.LogConfig
|
||||
|
||||
out := inspectFieldJSON(c, "test", "HostConfig.LogConfig")
|
||||
|
||||
err := json.NewDecoder(strings.NewReader(out)).Decode(&logConfig)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%v", out))
|
||||
|
||||
c.Assert(logConfig.Type, checker.Equals, "json-file")
|
||||
c.Assert(logConfig.Config["max-file"], checker.Equals, "42", check.Commentf("%v", logConfig))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectNoSizeFlagContainer(c *check.C) {
|
||||
|
||||
//Both the container and image are named busybox. docker inspect will fetch container
|
||||
//JSON SizeRw and SizeRootFs field. If there is no flag --size/-s, there are no size fields.
|
||||
|
||||
runSleepingContainer(c, "--name=busybox", "-d")
|
||||
|
||||
formatStr := "--format={{.SizeRw}},{{.SizeRootFs}}"
|
||||
out, _ := dockerCmd(c, "inspect", "--type=container", formatStr, "busybox")
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, "<nil>,<nil>", check.Commentf("Expected not to display size info: %s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectSizeFlagContainer(c *check.C) {
|
||||
runSleepingContainer(c, "--name=busybox", "-d")
|
||||
|
||||
formatStr := "--format='{{.SizeRw}},{{.SizeRootFs}}'"
|
||||
out, _ := dockerCmd(c, "inspect", "-s", "--type=container", formatStr, "busybox")
|
||||
sz := strings.Split(out, ",")
|
||||
|
||||
c.Assert(strings.TrimSpace(sz[0]), check.Not(check.Equals), "<nil>")
|
||||
c.Assert(strings.TrimSpace(sz[1]), check.Not(check.Equals), "<nil>")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectTemplateError(c *check.C) {
|
||||
// Template parsing error for both the container and image.
|
||||
|
||||
runSleepingContainer(c, "--name=container1", "-d")
|
||||
|
||||
out, _, err := dockerCmdWithError("inspect", "--type=container", "--format='Format container: {{.ThisDoesNotExist}}'", "container1")
|
||||
c.Assert(err, check.Not(check.IsNil))
|
||||
c.Assert(out, checker.Contains, "Template parsing error")
|
||||
|
||||
out, _, err = dockerCmdWithError("inspect", "--type=image", "--format='Format container: {{.ThisDoesNotExist}}'", "busybox")
|
||||
c.Assert(err, check.Not(check.IsNil))
|
||||
c.Assert(out, checker.Contains, "Template parsing error")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectJSONFields(c *check.C) {
|
||||
runSleepingContainer(c, "--name=busybox", "-d")
|
||||
out, _, err := dockerCmdWithError("inspect", "--type=container", "--format={{.HostConfig.Dns}}", "busybox")
|
||||
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(out, checker.Equals, "[]\n")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectByPrefix(c *check.C) {
|
||||
id := inspectField(c, "busybox", "Id")
|
||||
c.Assert(id, checker.HasPrefix, "sha256:")
|
||||
|
||||
id2 := inspectField(c, id[:12], "Id")
|
||||
c.Assert(id, checker.Equals, id2)
|
||||
|
||||
id3 := inspectField(c, strings.TrimPrefix(id, "sha256:")[:12], "Id")
|
||||
c.Assert(id, checker.Equals, id3)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectStopWhenNotFound(c *check.C) {
|
||||
runSleepingContainer(c, "--name=busybox1", "-d")
|
||||
runSleepingContainer(c, "--name=busybox2", "-d")
|
||||
result := dockerCmdWithResult("inspect", "--type=container", "--format='{{.Name}}'", "busybox1", "busybox2", "missing")
|
||||
|
||||
c.Assert(result.Error, checker.Not(check.IsNil))
|
||||
c.Assert(result.Stdout(), checker.Contains, "busybox1")
|
||||
c.Assert(result.Stdout(), checker.Contains, "busybox2")
|
||||
c.Assert(result.Stderr(), checker.Contains, "Error: No such container: missing")
|
||||
|
||||
// test inspect would not fast fail
|
||||
result = dockerCmdWithResult("inspect", "--type=container", "--format='{{.Name}}'", "missing", "busybox1", "busybox2")
|
||||
|
||||
c.Assert(result.Error, checker.Not(check.IsNil))
|
||||
c.Assert(result.Stdout(), checker.Contains, "busybox1")
|
||||
c.Assert(result.Stdout(), checker.Contains, "busybox2")
|
||||
c.Assert(result.Stderr(), checker.Contains, "Error: No such container: missing")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectHistory(c *check.C) {
|
||||
dockerCmd(c, "run", "--name=testcont", "busybox", "echo", "hello")
|
||||
dockerCmd(c, "commit", "-m", "test comment", "testcont", "testimg")
|
||||
out, _, err := dockerCmdWithError("inspect", "--format='{{.Comment}}'", "testimg")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(out, checker.Contains, "test comment")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectContainerNetworkDefault(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
contName := "test1"
|
||||
dockerCmd(c, "run", "--name", contName, "-d", "busybox", "top")
|
||||
netOut, _ := dockerCmd(c, "network", "inspect", "--format={{.ID}}", "bridge")
|
||||
out := inspectField(c, contName, "NetworkSettings.Networks")
|
||||
c.Assert(out, checker.Contains, "bridge")
|
||||
out = inspectField(c, contName, "NetworkSettings.Networks.bridge.NetworkID")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, strings.TrimSpace(netOut))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectContainerNetworkCustom(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
netOut, _ := dockerCmd(c, "network", "create", "net1")
|
||||
dockerCmd(c, "run", "--name=container1", "--net=net1", "-d", "busybox", "top")
|
||||
out := inspectField(c, "container1", "NetworkSettings.Networks")
|
||||
c.Assert(out, checker.Contains, "net1")
|
||||
out = inspectField(c, "container1", "NetworkSettings.Networks.net1.NetworkID")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, strings.TrimSpace(netOut))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectRootFS(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("inspect", "busybox")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
var imageJSON []types.ImageInspect
|
||||
err = json.Unmarshal([]byte(out), &imageJSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(len(imageJSON[0].RootFS.Layers), checker.GreaterOrEqualThan, 1)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectAmpersand(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
name := "test"
|
||||
out, _ := dockerCmd(c, "run", "--name", name, "--env", `TEST_ENV="soanni&rtr"`, "busybox", "env")
|
||||
c.Assert(out, checker.Contains, `soanni&rtr`)
|
||||
out, _ = dockerCmd(c, "inspect", name)
|
||||
c.Assert(out, checker.Contains, `soanni&rtr`)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectPlugin(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, IsAmd64, Network)
|
||||
_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err := dockerCmdWithError("inspect", "--type", "plugin", "--format", "{{.Name}}", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, pNameWithTag)
|
||||
|
||||
out, _, err = dockerCmdWithError("inspect", "--format", "{{.Name}}", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, pNameWithTag)
|
||||
|
||||
// Even without tag the inspect still work
|
||||
out, _, err = dockerCmdWithError("inspect", "--type", "plugin", "--format", "{{.Name}}", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, pNameWithTag)
|
||||
|
||||
out, _, err = dockerCmdWithError("inspect", "--format", "{{.Name}}", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, pNameWithTag)
|
||||
|
||||
_, _, err = dockerCmdWithError("plugin", "disable", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, pNameWithTag)
|
||||
}
|
||||
|
||||
// Test case for 29185
|
||||
func (s *DockerSuite) TestInspectUnknownObject(c *check.C) {
|
||||
// This test should work on both Windows and Linux
|
||||
out, _, err := dockerCmdWithError("inspect", "foobar")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "Error: No such object: foobar")
|
||||
c.Assert(err.Error(), checker.Contains, "Error: No such object: foobar")
|
||||
}
|
239
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_links_test.go
generated
vendored
Normal file
239
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_links_test.go
generated
vendored
Normal file
|
@ -0,0 +1,239 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestLinksPingUnlinkedContainers(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
_, exitCode, err := dockerCmdWithError("run", "--rm", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
|
||||
|
||||
// run ping failed with error
|
||||
c.Assert(exitCode, checker.Equals, 1, check.Commentf("error: %v", err))
|
||||
}
|
||||
|
||||
// Test for appropriate error when calling --link with an invalid target container
|
||||
func (s *DockerSuite) TestLinksInvalidContainerTarget(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _, err := dockerCmdWithError("run", "--link", "bogus:alias", "busybox", "true")
|
||||
|
||||
// an invalid container target should produce an error
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
// an invalid container target should produce an error
|
||||
// note: convert the output to lowercase first as the error string
|
||||
// capitalization was changed after API version 1.32
|
||||
c.Assert(strings.ToLower(out), checker.Contains, "could not get container")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksPingLinkedContainers(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// Test with the three different ways of specifying the default network on Linux
|
||||
testLinkPingOnNetwork(c, "")
|
||||
testLinkPingOnNetwork(c, "default")
|
||||
testLinkPingOnNetwork(c, "bridge")
|
||||
}
|
||||
|
||||
func testLinkPingOnNetwork(c *check.C, network string) {
|
||||
var postArgs []string
|
||||
if network != "" {
|
||||
postArgs = append(postArgs, []string{"--net", network}...)
|
||||
}
|
||||
postArgs = append(postArgs, []string{"busybox", "top"}...)
|
||||
runArgs1 := append([]string{"run", "-d", "--name", "container1", "--hostname", "fred"}, postArgs...)
|
||||
runArgs2 := append([]string{"run", "-d", "--name", "container2", "--hostname", "wilma"}, postArgs...)
|
||||
|
||||
// Run the two named containers
|
||||
dockerCmd(c, runArgs1...)
|
||||
dockerCmd(c, runArgs2...)
|
||||
|
||||
postArgs = []string{}
|
||||
if network != "" {
|
||||
postArgs = append(postArgs, []string{"--net", network}...)
|
||||
}
|
||||
postArgs = append(postArgs, []string{"busybox", "sh", "-c"}...)
|
||||
|
||||
// Format a run for a container which links to the other two
|
||||
runArgs := append([]string{"run", "--rm", "--link", "container1:alias1", "--link", "container2:alias2"}, postArgs...)
|
||||
pingCmd := "ping -c 1 %s -W 1 && ping -c 1 %s -W 1"
|
||||
|
||||
// test ping by alias, ping by name, and ping by hostname
|
||||
// 1. Ping by alias
|
||||
dockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "alias1", "alias2"))...)
|
||||
// 2. Ping by container name
|
||||
dockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "container1", "container2"))...)
|
||||
// 3. Ping by hostname
|
||||
dockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "fred", "wilma"))...)
|
||||
|
||||
// Clean for next round
|
||||
dockerCmd(c, "rm", "-f", "container1")
|
||||
dockerCmd(c, "rm", "-f", "container2")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksPingLinkedContainersAfterRename(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
|
||||
idA := strings.TrimSpace(out)
|
||||
out, _ = dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
|
||||
idB := strings.TrimSpace(out)
|
||||
dockerCmd(c, "rename", "container1", "container_new")
|
||||
dockerCmd(c, "run", "--rm", "--link", "container_new:alias1", "--link", "container2:alias2", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
|
||||
dockerCmd(c, "kill", idA)
|
||||
dockerCmd(c, "kill", idB)
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksInspectLinksStarted(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
|
||||
dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
|
||||
dockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "top")
|
||||
links := inspectFieldJSON(c, "testinspectlink", "HostConfig.Links")
|
||||
|
||||
var result []string
|
||||
err := json.Unmarshal([]byte(links), &result)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var expected = []string{
|
||||
"/container1:/testinspectlink/alias1",
|
||||
"/container2:/testinspectlink/alias2",
|
||||
}
|
||||
sort.Strings(result)
|
||||
c.Assert(result, checker.DeepEquals, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksInspectLinksStopped(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
|
||||
dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
|
||||
dockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "true")
|
||||
links := inspectFieldJSON(c, "testinspectlink", "HostConfig.Links")
|
||||
|
||||
var result []string
|
||||
err := json.Unmarshal([]byte(links), &result)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var expected = []string{
|
||||
"/container1:/testinspectlink/alias1",
|
||||
"/container2:/testinspectlink/alias2",
|
||||
}
|
||||
sort.Strings(result)
|
||||
c.Assert(result, checker.DeepEquals, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksNotStartedParentNotFail(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "create", "--name=first", "busybox", "top")
|
||||
dockerCmd(c, "create", "--name=second", "--link=first:first", "busybox", "top")
|
||||
dockerCmd(c, "start", "first")
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksHostsFilesInject(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon, ExecSupport)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-itd", "--name", "one", "busybox", "top")
|
||||
idOne := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "run", "-itd", "--name", "two", "--link", "one:onetwo", "busybox", "top")
|
||||
idTwo := strings.TrimSpace(out)
|
||||
|
||||
c.Assert(waitRun(idTwo), checker.IsNil)
|
||||
|
||||
readContainerFileWithExec(c, idOne, "/etc/hosts")
|
||||
contentTwo := readContainerFileWithExec(c, idTwo, "/etc/hosts")
|
||||
// Host is not present in updated hosts file
|
||||
c.Assert(string(contentTwo), checker.Contains, "onetwo")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksUpdateOnRestart(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon, ExecSupport)
|
||||
dockerCmd(c, "run", "-d", "--name", "one", "busybox", "top")
|
||||
out, _ := dockerCmd(c, "run", "-d", "--name", "two", "--link", "one:onetwo", "--link", "one:one", "busybox", "top")
|
||||
id := strings.TrimSpace(string(out))
|
||||
|
||||
realIP := inspectField(c, "one", "NetworkSettings.Networks.bridge.IPAddress")
|
||||
content := readContainerFileWithExec(c, id, "/etc/hosts")
|
||||
|
||||
getIP := func(hosts []byte, hostname string) string {
|
||||
re := regexp.MustCompile(fmt.Sprintf(`(\S*)\t%s`, regexp.QuoteMeta(hostname)))
|
||||
matches := re.FindSubmatch(hosts)
|
||||
c.Assert(matches, checker.NotNil, check.Commentf("Hostname %s have no matches in hosts", hostname))
|
||||
return string(matches[1])
|
||||
}
|
||||
ip := getIP(content, "one")
|
||||
c.Assert(ip, checker.Equals, realIP)
|
||||
|
||||
ip = getIP(content, "onetwo")
|
||||
c.Assert(ip, checker.Equals, realIP)
|
||||
|
||||
dockerCmd(c, "restart", "one")
|
||||
realIP = inspectField(c, "one", "NetworkSettings.Networks.bridge.IPAddress")
|
||||
|
||||
content = readContainerFileWithExec(c, id, "/etc/hosts")
|
||||
ip = getIP(content, "one")
|
||||
c.Assert(ip, checker.Equals, realIP)
|
||||
|
||||
ip = getIP(content, "onetwo")
|
||||
c.Assert(ip, checker.Equals, realIP)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksEnvs(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "-e", "e1=", "-e", "e2=v2", "-e", "e3=v3=v3", "--name=first", "busybox", "top")
|
||||
out, _ := dockerCmd(c, "run", "--name=second", "--link=first:first", "busybox", "env")
|
||||
c.Assert(out, checker.Contains, "FIRST_ENV_e1=\n")
|
||||
c.Assert(out, checker.Contains, "FIRST_ENV_e2=v2")
|
||||
c.Assert(out, checker.Contains, "FIRST_ENV_e3=v3=v3")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinkShortDefinition(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "--name", "shortlinkdef", "busybox", "top")
|
||||
|
||||
cid := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(cid), checker.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "run", "-d", "--name", "link2", "--link", "shortlinkdef", "busybox", "top")
|
||||
|
||||
cid2 := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(cid2), checker.IsNil)
|
||||
|
||||
links := inspectFieldJSON(c, cid2, "HostConfig.Links")
|
||||
c.Assert(links, checker.Equals, "[\"/shortlinkdef:/link2/shortlinkdef\"]")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksNetworkHostContainer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
dockerCmd(c, "run", "-d", "--net", "host", "--name", "host_container", "busybox", "top")
|
||||
out, _, err := dockerCmdWithError("run", "--name", "should_fail", "--link", "host_container:tester", "busybox", "true")
|
||||
|
||||
// Running container linking to a container with --net host should have failed
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
// Running container linking to a container with --net host should have failed
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetworkAndLinks.Error())
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksEtcHostsRegularFile(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
out, _ := dockerCmd(c, "run", "--net=host", "busybox", "ls", "-la", "/etc/hosts")
|
||||
// /etc/hosts should be a regular file
|
||||
c.Assert(out, checker.Matches, "^-.+\n")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLinksMultipleWithSameName(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "--name=upstream-a", "busybox", "top")
|
||||
dockerCmd(c, "run", "-d", "--name=upstream-b", "busybox", "top")
|
||||
dockerCmd(c, "run", "--link", "upstream-a:upstream", "--link", "upstream-b:upstream", "busybox", "sh", "-c", "ping -c 1 upstream")
|
||||
}
|
30
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_login_test.go
generated
vendored
Normal file
30
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_login_test.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os/exec"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestLoginWithoutTTY(c *check.C) {
|
||||
cmd := exec.Command(dockerBinary, "login")
|
||||
|
||||
// Send to stdin so the process does not get the TTY
|
||||
cmd.Stdin = bytes.NewBufferString("buffer test string \n")
|
||||
|
||||
// run the command and block until it's done
|
||||
err := cmd.Run()
|
||||
c.Assert(err, checker.NotNil) //"Expected non nil err when logging in & TTY not available"
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthHtpasswdSuite) TestLoginToPrivateRegistry(c *check.C) {
|
||||
// wrong credentials
|
||||
out, _, err := dockerCmdWithError("login", "-u", s.reg.Username(), "-p", "WRONGPASSWORD", privateRegistryURL)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "401 Unauthorized")
|
||||
|
||||
// now it's fine
|
||||
dockerCmd(c, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
|
||||
}
|
106
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_logout_test.go
generated
vendored
Normal file
106
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_logout_test.go
generated
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithExternalAuth(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
|
||||
osPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", osPath)
|
||||
|
||||
workingDir, err := os.Getwd()
|
||||
c.Assert(err, checker.IsNil)
|
||||
absolute, err := filepath.Abs(filepath.Join(workingDir, "fixtures", "auth"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
testPath := fmt.Sprintf("%s%c%s", osPath, filepath.ListSeparator, absolute)
|
||||
|
||||
os.Setenv("PATH", testPath)
|
||||
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox:authtest", privateRegistryURL)
|
||||
|
||||
tmp, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
externalAuthConfig := `{ "credsStore": "shell-test" }`
|
||||
|
||||
configPath := filepath.Join(tmp, "config.json")
|
||||
err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = s.d.Cmd("--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
b, err := ioutil.ReadFile(configPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(b), checker.Not(checker.Contains), "\"auth\":")
|
||||
c.Assert(string(b), checker.Contains, privateRegistryURL)
|
||||
|
||||
_, err = s.d.Cmd("--config", tmp, "tag", "busybox", repoName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = s.d.Cmd("--config", tmp, "push", repoName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = s.d.Cmd("--config", tmp, "logout", privateRegistryURL)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
b, err = ioutil.ReadFile(configPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(b), checker.Not(checker.Contains), privateRegistryURL)
|
||||
|
||||
// check I cannot pull anymore
|
||||
out, err := s.d.Cmd("--config", tmp, "pull", repoName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "no basic auth credentials")
|
||||
}
|
||||
|
||||
// #23100
|
||||
func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithWrongHostnamesStored(c *check.C) {
|
||||
osPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", osPath)
|
||||
|
||||
workingDir, err := os.Getwd()
|
||||
c.Assert(err, checker.IsNil)
|
||||
absolute, err := filepath.Abs(filepath.Join(workingDir, "fixtures", "auth"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
testPath := fmt.Sprintf("%s%c%s", osPath, filepath.ListSeparator, absolute)
|
||||
|
||||
os.Setenv("PATH", testPath)
|
||||
|
||||
cmd := exec.Command("docker-credential-shell-test", "store")
|
||||
stdin := bytes.NewReader([]byte(fmt.Sprintf(`{"ServerURL": "https://%s", "Username": "%s", "Secret": "%s"}`, privateRegistryURL, s.reg.Username(), s.reg.Password())))
|
||||
cmd.Stdin = stdin
|
||||
c.Assert(cmd.Run(), checker.IsNil)
|
||||
|
||||
tmp, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
externalAuthConfig := fmt.Sprintf(`{ "auths": {"https://%s": {}}, "credsStore": "shell-test" }`, privateRegistryURL)
|
||||
|
||||
configPath := filepath.Join(tmp, "config.json")
|
||||
err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
|
||||
|
||||
b, err := ioutil.ReadFile(configPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(b), checker.Contains, fmt.Sprintf("\"https://%s\": {}", privateRegistryURL))
|
||||
c.Assert(string(b), checker.Contains, fmt.Sprintf("\"%s\": {}", privateRegistryURL))
|
||||
|
||||
dockerCmd(c, "--config", tmp, "logout", privateRegistryURL)
|
||||
|
||||
b, err = ioutil.ReadFile(configPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(b), checker.Not(checker.Contains), fmt.Sprintf("\"https://%s\": {}", privateRegistryURL))
|
||||
c.Assert(string(b), checker.Not(checker.Contains), fmt.Sprintf("\"%s\": {}", privateRegistryURL))
|
||||
}
|
32
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_logs_bench_test.go
generated
vendored
Normal file
32
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_logs_bench_test.go
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) BenchmarkLogsCLIRotateFollow(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "--log-opt", "max-size=1b", "--log-opt", "max-file=10", "busybox", "sh", "-c", "while true; do usleep 50000; echo hello; done")
|
||||
id := strings.TrimSpace(out)
|
||||
ch := make(chan error, 1)
|
||||
go func() {
|
||||
ch <- nil
|
||||
out, _, _ := dockerCmdWithError("logs", "-f", id)
|
||||
// if this returns at all, it's an error
|
||||
ch <- fmt.Errorf(out)
|
||||
}()
|
||||
|
||||
<-ch
|
||||
select {
|
||||
case <-time.After(30 * time.Second):
|
||||
// ran for 30 seconds with no problem
|
||||
return
|
||||
case err := <-ch:
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
336
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_logs_test.go
generated
vendored
Normal file
336
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_logs_test.go
generated
vendored
Normal file
|
@ -0,0 +1,336 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// This used to work, it test a log of PageSize-1 (gh#4851)
|
||||
func (s *DockerSuite) TestLogsContainerSmallerThanPage(c *check.C) {
|
||||
testLogsContainerPagination(c, 32767)
|
||||
}
|
||||
|
||||
// Regression test: When going over the PageSize, it used to panic (gh#4851)
|
||||
func (s *DockerSuite) TestLogsContainerBiggerThanPage(c *check.C) {
|
||||
testLogsContainerPagination(c, 32768)
|
||||
}
|
||||
|
||||
// Regression test: When going much over the PageSize, it used to block (gh#4851)
|
||||
func (s *DockerSuite) TestLogsContainerMuchBiggerThanPage(c *check.C) {
|
||||
testLogsContainerPagination(c, 33000)
|
||||
}
|
||||
|
||||
func testLogsContainerPagination(c *check.C, testLen int) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n = >> a.a; done; echo >> a.a; cat a.a", testLen))
|
||||
id := strings.TrimSpace(out)
|
||||
dockerCmd(c, "wait", id)
|
||||
out, _ = dockerCmd(c, "logs", id)
|
||||
c.Assert(out, checker.HasLen, testLen+1)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsTimestamps(c *check.C) {
|
||||
testLen := 100
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo = >> a.a; done; cat a.a", testLen))
|
||||
|
||||
id := strings.TrimSpace(out)
|
||||
dockerCmd(c, "wait", id)
|
||||
|
||||
out, _ = dockerCmd(c, "logs", "-t", id)
|
||||
|
||||
lines := strings.Split(out, "\n")
|
||||
|
||||
c.Assert(lines, checker.HasLen, testLen+1)
|
||||
|
||||
ts := regexp.MustCompile(`^.* `)
|
||||
|
||||
for _, l := range lines {
|
||||
if l != "" {
|
||||
_, err := time.Parse(jsonmessage.RFC3339NanoFixed+" ", ts.FindString(l))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Failed to parse timestamp from %v", l))
|
||||
// ensure we have padded 0's
|
||||
c.Assert(l[29], checker.Equals, uint8('Z'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsSeparateStderr(c *check.C) {
|
||||
msg := "stderr_log"
|
||||
out := cli.DockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg)).Combined()
|
||||
id := strings.TrimSpace(out)
|
||||
cli.DockerCmd(c, "wait", id)
|
||||
cli.DockerCmd(c, "logs", id).Assert(c, icmd.Expected{
|
||||
Out: "",
|
||||
Err: msg,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsStderrInStdout(c *check.C) {
|
||||
// TODO Windows: Needs investigation why this fails. Obtained string includes
|
||||
// a bunch of ANSI escape sequences before the "stderr_log" message.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
msg := "stderr_log"
|
||||
out := cli.DockerCmd(c, "run", "-d", "-t", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg)).Combined()
|
||||
id := strings.TrimSpace(out)
|
||||
cli.DockerCmd(c, "wait", id)
|
||||
|
||||
cli.DockerCmd(c, "logs", id).Assert(c, icmd.Expected{
|
||||
Out: msg,
|
||||
Err: "",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsTail(c *check.C) {
|
||||
testLen := 100
|
||||
out := cli.DockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen)).Combined()
|
||||
|
||||
id := strings.TrimSpace(out)
|
||||
cli.DockerCmd(c, "wait", id)
|
||||
|
||||
out = cli.DockerCmd(c, "logs", "--tail", "0", id).Combined()
|
||||
lines := strings.Split(out, "\n")
|
||||
c.Assert(lines, checker.HasLen, 1)
|
||||
|
||||
out = cli.DockerCmd(c, "logs", "--tail", "5", id).Combined()
|
||||
lines = strings.Split(out, "\n")
|
||||
c.Assert(lines, checker.HasLen, 6)
|
||||
|
||||
out = cli.DockerCmd(c, "logs", "--tail", "99", id).Combined()
|
||||
lines = strings.Split(out, "\n")
|
||||
c.Assert(lines, checker.HasLen, 100)
|
||||
|
||||
out = cli.DockerCmd(c, "logs", "--tail", "all", id).Combined()
|
||||
lines = strings.Split(out, "\n")
|
||||
c.Assert(lines, checker.HasLen, testLen+1)
|
||||
|
||||
out = cli.DockerCmd(c, "logs", "--tail", "-1", id).Combined()
|
||||
lines = strings.Split(out, "\n")
|
||||
c.Assert(lines, checker.HasLen, testLen+1)
|
||||
|
||||
out = cli.DockerCmd(c, "logs", "--tail", "random", id).Combined()
|
||||
lines = strings.Split(out, "\n")
|
||||
c.Assert(lines, checker.HasLen, testLen+1)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsFollowStopped(c *check.C) {
|
||||
dockerCmd(c, "run", "--name=test", "busybox", "echo", "hello")
|
||||
id := getIDByName(c, "test")
|
||||
|
||||
logsCmd := exec.Command(dockerBinary, "logs", "-f", id)
|
||||
c.Assert(logsCmd.Start(), checker.IsNil)
|
||||
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
errChan <- logsCmd.Wait()
|
||||
close(errChan)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errChan:
|
||||
c.Assert(err, checker.IsNil)
|
||||
case <-time.After(30 * time.Second):
|
||||
c.Fatal("Following logs is hanged")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsSince(c *check.C) {
|
||||
name := "testlogssince"
|
||||
dockerCmd(c, "run", "--name="+name, "busybox", "/bin/sh", "-c", "for i in $(seq 1 3); do sleep 2; echo log$i; done")
|
||||
out, _ := dockerCmd(c, "logs", "-t", name)
|
||||
|
||||
log2Line := strings.Split(strings.Split(out, "\n")[1], " ")
|
||||
t, err := time.Parse(time.RFC3339Nano, log2Line[0]) // the timestamp log2 is written
|
||||
c.Assert(err, checker.IsNil)
|
||||
since := t.Unix() + 1 // add 1s so log1 & log2 doesn't show up
|
||||
out, _ = dockerCmd(c, "logs", "-t", fmt.Sprintf("--since=%v", since), name)
|
||||
|
||||
// Skip 2 seconds
|
||||
unexpected := []string{"log1", "log2"}
|
||||
for _, v := range unexpected {
|
||||
c.Assert(out, checker.Not(checker.Contains), v, check.Commentf("unexpected log message returned, since=%v", since))
|
||||
}
|
||||
|
||||
// Test to make sure a bad since format is caught by the client
|
||||
out, _, _ = dockerCmdWithError("logs", "-t", "--since=2006-01-02T15:04:0Z", name)
|
||||
c.Assert(out, checker.Contains, "cannot parse \"0Z\" as \"05\"", check.Commentf("bad since format passed to server"))
|
||||
|
||||
// Test with default value specified and parameter omitted
|
||||
expected := []string{"log1", "log2", "log3"}
|
||||
for _, cmd := range [][]string{
|
||||
{"logs", "-t", name},
|
||||
{"logs", "-t", "--since=0", name},
|
||||
} {
|
||||
result := icmd.RunCommand(dockerBinary, cmd...)
|
||||
result.Assert(c, icmd.Success)
|
||||
for _, v := range expected {
|
||||
c.Assert(result.Combined(), checker.Contains, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsSinceFutureFollow(c *check.C) {
|
||||
// TODO Windows TP5 - Figure out why this test is so flakey. Disabled for now.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "testlogssincefuturefollow"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "busybox", "/bin/sh", "-c", `for i in $(seq 1 5); do echo log$i; sleep 1; done`)
|
||||
|
||||
// Extract one timestamp from the log file to give us a starting point for
|
||||
// our `--since` argument. Because the log producer runs in the background,
|
||||
// we need to check repeatedly for some output to be produced.
|
||||
var timestamp string
|
||||
for i := 0; i != 100 && timestamp == ""; i++ {
|
||||
if out, _ := dockerCmd(c, "logs", "-t", name); out == "" {
|
||||
time.Sleep(time.Millisecond * 100) // Retry
|
||||
} else {
|
||||
timestamp = strings.Split(strings.Split(out, "\n")[0], " ")[0]
|
||||
}
|
||||
}
|
||||
|
||||
c.Assert(timestamp, checker.Not(checker.Equals), "")
|
||||
t, err := time.Parse(time.RFC3339Nano, timestamp)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
since := t.Unix() + 2
|
||||
out, _ := dockerCmd(c, "logs", "-t", "-f", fmt.Sprintf("--since=%v", since), name)
|
||||
c.Assert(out, checker.Not(checker.HasLen), 0, check.Commentf("cannot read from empty log"))
|
||||
lines := strings.Split(strings.TrimSpace(out), "\n")
|
||||
for _, v := range lines {
|
||||
ts, err := time.Parse(time.RFC3339Nano, strings.Split(v, " ")[0])
|
||||
c.Assert(err, checker.IsNil, check.Commentf("cannot parse timestamp output from log: '%v'", v))
|
||||
c.Assert(ts.Unix() >= since, checker.Equals, true, check.Commentf("earlier log found. since=%v logdate=%v", since, ts))
|
||||
}
|
||||
}
|
||||
|
||||
// Regression test for #8832
|
||||
func (s *DockerSuite) TestLogsFollowSlowStdoutConsumer(c *check.C) {
|
||||
// TODO Windows: Fix this test for TP5.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
expected := 150000
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", fmt.Sprintf("usleep 600000; yes X | head -c %d", expected))
|
||||
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
stopSlowRead := make(chan bool)
|
||||
|
||||
go func() {
|
||||
dockerCmd(c, "wait", id)
|
||||
stopSlowRead <- true
|
||||
}()
|
||||
|
||||
logCmd := exec.Command(dockerBinary, "logs", "-f", id)
|
||||
stdout, err := logCmd.StdoutPipe()
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(logCmd.Start(), checker.IsNil)
|
||||
defer func() { go logCmd.Wait() }()
|
||||
|
||||
// First read slowly
|
||||
bytes1, err := ConsumeWithSpeed(stdout, 10, 50*time.Millisecond, stopSlowRead)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// After the container has finished we can continue reading fast
|
||||
bytes2, err := ConsumeWithSpeed(stdout, 32*1024, 0, nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(logCmd.Wait(), checker.IsNil)
|
||||
|
||||
actual := bytes1 + bytes2
|
||||
c.Assert(actual, checker.Equals, expected)
|
||||
}
|
||||
|
||||
// ConsumeWithSpeed reads chunkSize bytes from reader before sleeping
|
||||
// for interval duration. Returns total read bytes. Send true to the
|
||||
// stop channel to return before reading to EOF on the reader.
|
||||
func ConsumeWithSpeed(reader io.Reader, chunkSize int, interval time.Duration, stop chan bool) (n int, err error) {
|
||||
buffer := make([]byte, chunkSize)
|
||||
for {
|
||||
var readBytes int
|
||||
readBytes, err = reader.Read(buffer)
|
||||
n += readBytes
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
case <-time.After(interval):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsFollowGoroutinesWithStdout(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true; do echo hello; sleep 2; done")
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), checker.IsNil)
|
||||
|
||||
nroutines, err := getGoroutineNumber()
|
||||
c.Assert(err, checker.IsNil)
|
||||
cmd := exec.Command(dockerBinary, "logs", "-f", id)
|
||||
r, w := io.Pipe()
|
||||
cmd.Stdout = w
|
||||
c.Assert(cmd.Start(), checker.IsNil)
|
||||
go cmd.Wait()
|
||||
|
||||
// Make sure pipe is written to
|
||||
chErr := make(chan error)
|
||||
go func() {
|
||||
b := make([]byte, 1)
|
||||
_, err := r.Read(b)
|
||||
chErr <- err
|
||||
}()
|
||||
c.Assert(<-chErr, checker.IsNil)
|
||||
c.Assert(cmd.Process.Kill(), checker.IsNil)
|
||||
r.Close()
|
||||
cmd.Wait()
|
||||
// NGoroutines is not updated right away, so we need to wait before failing
|
||||
c.Assert(waitForGoroutines(nroutines), checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsFollowGoroutinesNoOutput(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 2; done")
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), checker.IsNil)
|
||||
|
||||
nroutines, err := getGoroutineNumber()
|
||||
c.Assert(err, checker.IsNil)
|
||||
cmd := exec.Command(dockerBinary, "logs", "-f", id)
|
||||
c.Assert(cmd.Start(), checker.IsNil)
|
||||
go cmd.Wait()
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
c.Assert(cmd.Process.Kill(), checker.IsNil)
|
||||
cmd.Wait()
|
||||
|
||||
// NGoroutines is not updated right away, so we need to wait before failing
|
||||
c.Assert(waitForGoroutines(nroutines), checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsCLIContainerNotFound(c *check.C) {
|
||||
name := "testlogsnocontainer"
|
||||
out, _, _ := dockerCmdWithError("logs", name)
|
||||
message := fmt.Sprintf("No such container: %s\n", name)
|
||||
c.Assert(out, checker.Contains, message)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestLogsWithDetails(c *check.C) {
|
||||
dockerCmd(c, "run", "--name=test", "--label", "foo=bar", "-e", "baz=qux", "--log-opt", "labels=foo", "--log-opt", "env=baz", "busybox", "echo", "hello")
|
||||
out, _ := dockerCmd(c, "logs", "--details", "--timestamps", "test")
|
||||
|
||||
logFields := strings.Fields(strings.TrimSpace(out))
|
||||
c.Assert(len(logFields), checker.Equals, 3, check.Commentf("%s", out))
|
||||
|
||||
details := strings.Split(logFields[1], ",")
|
||||
c.Assert(details, checker.HasLen, 2)
|
||||
c.Assert(details[0], checker.Equals, "baz=qux")
|
||||
c.Assert(details[1], checker.Equals, "foo=bar")
|
||||
}
|
96
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_netmode_test.go
generated
vendored
Normal file
96
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_netmode_test.go
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// GH14530. Validates combinations of --net= with other options
|
||||
|
||||
// stringCheckPS is how the output of PS starts in order to validate that
|
||||
// the command executed in a container did really run PS correctly.
|
||||
const stringCheckPS = "PID USER"
|
||||
|
||||
// DockerCmdWithFail executes a docker command that is supposed to fail and returns
|
||||
// the output, the exit code. If the command returns a Nil error, it will fail and
|
||||
// stop the tests.
|
||||
func dockerCmdWithFail(c *check.C, args ...string) (string, int) {
|
||||
out, status, err := dockerCmdWithError(args...)
|
||||
c.Assert(err, check.NotNil, check.Commentf("%v", out))
|
||||
return out, status
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestNetHostnameWithNetHost(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--net=host", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, stringCheckPS)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestNetHostname(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-h=name", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, stringCheckPS)
|
||||
|
||||
out, _ = dockerCmd(c, "run", "-h=name", "--net=bridge", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, stringCheckPS)
|
||||
|
||||
out, _ = dockerCmd(c, "run", "-h=name", "--net=none", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, stringCheckPS)
|
||||
|
||||
out, _ = dockerCmdWithFail(c, "run", "-h=name", "--net=container:other", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictNetworkHostname.Error())
|
||||
|
||||
out, _ = dockerCmdWithFail(c, "run", "--net=container", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, "invalid container format container:<name|id>")
|
||||
|
||||
out, _ = dockerCmdWithFail(c, "run", "--net=weird", "busybox", "ps")
|
||||
c.Assert(strings.ToLower(out), checker.Contains, "not found")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestConflictContainerNetworkAndLinks(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmdWithFail(c, "run", "--net=container:other", "--link=zip:zap", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictContainerNetworkAndLinks.Error())
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestConflictContainerNetworkHostAndLinks(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
out, _ := dockerCmdWithFail(c, "run", "--net=host", "--link=zip:zap", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetworkAndLinks.Error())
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestConflictNetworkModeNetHostAndOptions(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
out, _ := dockerCmdWithFail(c, "run", "--net=host", "--mac-address=92:d0:c6:0a:29:33", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictContainerNetworkAndMac.Error())
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestConflictNetworkModeAndOptions(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmdWithFail(c, "run", "--net=container:other", "--dns=8.8.8.8", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictNetworkAndDNS.Error())
|
||||
|
||||
out, _ = dockerCmdWithFail(c, "run", "--net=container:other", "--add-host=name:8.8.8.8", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictNetworkHosts.Error())
|
||||
|
||||
out, _ = dockerCmdWithFail(c, "run", "--net=container:other", "--mac-address=92:d0:c6:0a:29:33", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictContainerNetworkAndMac.Error())
|
||||
|
||||
out, _ = dockerCmdWithFail(c, "run", "--net=container:other", "-P", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictNetworkPublishPorts.Error())
|
||||
|
||||
out, _ = dockerCmdWithFail(c, "run", "--net=container:other", "-p", "8080", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictNetworkPublishPorts.Error())
|
||||
|
||||
out, _ = dockerCmdWithFail(c, "run", "--net=container:other", "--expose", "8000-9000", "busybox", "ps")
|
||||
c.Assert(out, checker.Contains, runconfig.ErrConflictNetworkExposePorts.Error())
|
||||
}
|
1833
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_network_unix_test.go
generated
vendored
Normal file
1833
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_network_unix_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
48
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_plugins_logdriver_test.go
generated
vendored
Normal file
48
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_plugins_logdriver_test.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestPluginLogDriver(c *check.C) {
|
||||
testRequires(c, IsAmd64, DaemonIsLinux)
|
||||
|
||||
pluginName := "cpuguy83/docker-logdriver-test:latest"
|
||||
|
||||
dockerCmd(c, "plugin", "install", pluginName)
|
||||
dockerCmd(c, "run", "--log-driver", pluginName, "--name=test", "busybox", "echo", "hello")
|
||||
out, _ := dockerCmd(c, "logs", "test")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "hello")
|
||||
|
||||
dockerCmd(c, "start", "-a", "test")
|
||||
out, _ = dockerCmd(c, "logs", "test")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "hello\nhello")
|
||||
|
||||
dockerCmd(c, "rm", "test")
|
||||
dockerCmd(c, "plugin", "disable", pluginName)
|
||||
dockerCmd(c, "plugin", "rm", pluginName)
|
||||
}
|
||||
|
||||
// Make sure log drivers are listed in info, and v2 plugins are not.
|
||||
func (s *DockerSuite) TestPluginLogDriverInfoList(c *check.C) {
|
||||
testRequires(c, IsAmd64, DaemonIsLinux)
|
||||
pluginName := "cpuguy83/docker-logdriver-test"
|
||||
|
||||
dockerCmd(c, "plugin", "install", pluginName)
|
||||
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
info, err := cli.Info(context.Background())
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
drivers := strings.Join(info.Plugins.Log, " ")
|
||||
c.Assert(drivers, checker.Contains, "json-file")
|
||||
c.Assert(drivers, checker.Not(checker.Contains), pluginName)
|
||||
}
|
493
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_plugins_test.go
generated
vendored
Normal file
493
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_plugins_test.go
generated
vendored
Normal file
|
@ -0,0 +1,493 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/docker/docker/internal/test/fixtures/plugin"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
var (
|
||||
pluginProcessName = "sample-volume-plugin"
|
||||
pName = "tiborvass/sample-volume-plugin"
|
||||
npName = "tiborvass/test-docker-netplugin"
|
||||
pTag = "latest"
|
||||
pNameWithTag = pName + ":" + pTag
|
||||
npNameWithTag = npName + ":" + pTag
|
||||
)
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginBasicOps(c *check.C) {
|
||||
plugin := ps.getPluginRepoWithTag()
|
||||
_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", plugin)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err := dockerCmdWithError("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, plugin)
|
||||
c.Assert(out, checker.Contains, "true")
|
||||
|
||||
id, _, err := dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", plugin)
|
||||
id = strings.TrimSpace(id)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "remove", plugin)
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "is enabled")
|
||||
|
||||
_, _, err = dockerCmdWithError("plugin", "disable", plugin)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "remove", plugin)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, plugin)
|
||||
|
||||
_, err = os.Stat(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "plugins", id))
|
||||
if !os.IsNotExist(err) {
|
||||
c.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginForceRemove(c *check.C) {
|
||||
pNameWithTag := ps.getPluginRepoWithTag()
|
||||
|
||||
_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, _ := dockerCmdWithError("plugin", "remove", pNameWithTag)
|
||||
c.Assert(out, checker.Contains, "is enabled")
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "remove", "--force", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, pNameWithTag)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPluginActive(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, IsAmd64, Network)
|
||||
|
||||
_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, _, err = dockerCmdWithError("volume", "create", "-d", pNameWithTag, "--name", "testvol1")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, _ := dockerCmdWithError("plugin", "disable", pNameWithTag)
|
||||
c.Assert(out, checker.Contains, "in use")
|
||||
|
||||
_, _, err = dockerCmdWithError("volume", "rm", "testvol1")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, _, err = dockerCmdWithError("plugin", "disable", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, pNameWithTag)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPluginActiveNetwork(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, IsAmd64, Network)
|
||||
_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", npNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err := dockerCmdWithError("network", "create", "-d", npNameWithTag, "test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
nID := strings.TrimSpace(out)
|
||||
|
||||
out, _, _ = dockerCmdWithError("plugin", "remove", npNameWithTag)
|
||||
c.Assert(out, checker.Contains, "is in use")
|
||||
|
||||
_, _, err = dockerCmdWithError("network", "rm", nID)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, _ = dockerCmdWithError("plugin", "remove", npNameWithTag)
|
||||
c.Assert(out, checker.Contains, "is enabled")
|
||||
|
||||
_, _, err = dockerCmdWithError("plugin", "disable", npNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "remove", npNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, npNameWithTag)
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginInstallDisable(c *check.C) {
|
||||
pName := ps.getPluginRepoWithTag()
|
||||
|
||||
out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", "--disable", pName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, pName)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, "false")
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "enable", pName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, pName)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "disable", pName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, pName)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "remove", pName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, pName)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPluginInstallDisableVolumeLs(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, IsAmd64, Network)
|
||||
out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", "--disable", pName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, pName)
|
||||
|
||||
dockerCmd(c, "volume", "ls")
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginSet(c *check.C) {
|
||||
client := testEnv.APIClient()
|
||||
|
||||
name := "test"
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
initialValue := "0"
|
||||
mntSrc := "foo"
|
||||
devPath := "/dev/bar"
|
||||
|
||||
// Create a new plugin with extra settings
|
||||
err := plugin.Create(ctx, client, name, func(cfg *plugin.Config) {
|
||||
cfg.Env = []types.PluginEnv{{Name: "DEBUG", Value: &initialValue, Settable: []string{"value"}}}
|
||||
cfg.Mounts = []types.PluginMount{
|
||||
{Name: "pmount1", Settable: []string{"source"}, Type: "none", Source: &mntSrc},
|
||||
{Name: "pmount2", Settable: []string{"source"}, Type: "none"}, // Mount without source is invalid.
|
||||
}
|
||||
cfg.Linux.Devices = []types.PluginDevice{
|
||||
{Name: "pdev1", Path: &devPath, Settable: []string{"path"}},
|
||||
{Name: "pdev2", Settable: []string{"path"}}, // Device without Path is invalid.
|
||||
}
|
||||
})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to create test plugin"))
|
||||
|
||||
env, _ := dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", name)
|
||||
c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=0]")
|
||||
|
||||
dockerCmd(c, "plugin", "set", name, "DEBUG=1")
|
||||
|
||||
env, _ = dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", name)
|
||||
c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=1]")
|
||||
|
||||
env, _ = dockerCmd(c, "plugin", "inspect", "-f", "{{with $mount := index .Settings.Mounts 0}}{{$mount.Source}}{{end}}", name)
|
||||
c.Assert(strings.TrimSpace(env), checker.Contains, mntSrc)
|
||||
|
||||
dockerCmd(c, "plugin", "set", name, "pmount1.source=bar")
|
||||
|
||||
env, _ = dockerCmd(c, "plugin", "inspect", "-f", "{{with $mount := index .Settings.Mounts 0}}{{$mount.Source}}{{end}}", name)
|
||||
c.Assert(strings.TrimSpace(env), checker.Contains, "bar")
|
||||
|
||||
out, _, err := dockerCmdWithError("plugin", "set", name, "pmount2.source=bar2")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "Plugin config has no mount source")
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "set", name, "pdev2.path=/dev/bar2")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "Plugin config has no device path")
|
||||
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginInstallArgs(c *check.C) {
|
||||
pName := path.Join(ps.registryHost(), "plugin", "testplugininstallwithargs")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
plugin.CreateInRegistry(ctx, pName, nil, func(cfg *plugin.Config) {
|
||||
cfg.Env = []types.PluginEnv{{Name: "DEBUG", Settable: []string{"value"}}}
|
||||
})
|
||||
|
||||
out, _ := dockerCmd(c, "plugin", "install", "--grant-all-permissions", "--disable", pName, "DEBUG=1")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, pName)
|
||||
|
||||
env, _ := dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", pName)
|
||||
c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=1]")
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginInstallImage(c *check.C) {
|
||||
testRequires(c, IsAmd64)
|
||||
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
// tag the image to upload it to the private registry
|
||||
dockerCmd(c, "tag", "busybox", repoName)
|
||||
// push the image to the registry
|
||||
dockerCmd(c, "push", repoName)
|
||||
|
||||
out, _, err := dockerCmdWithError("plugin", "install", repoName)
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, `Encountered remote "application/vnd.docker.container.image.v1+json"(image) when fetching`)
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginEnableDisableNegative(c *check.C) {
|
||||
pName := ps.getPluginRepoWithTag()
|
||||
|
||||
out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, pName)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "enable", pName)
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "already enabled")
|
||||
|
||||
_, _, err = dockerCmdWithError("plugin", "disable", pName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "disable", pName)
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "already disabled")
|
||||
|
||||
_, _, err = dockerCmdWithError("plugin", "remove", pName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginCreate(c *check.C) {
|
||||
name := "foo/bar-driver"
|
||||
temp, err := ioutil.TempDir("", "foo")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(temp)
|
||||
|
||||
data := `{"description": "foo plugin"}`
|
||||
err = ioutil.WriteFile(filepath.Join(temp, "config.json"), []byte(data), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = os.MkdirAll(filepath.Join(temp, "rootfs"), 0700)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err := dockerCmdWithError("plugin", "create", name, temp)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, name)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, name)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "create", name, temp)
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "already exist")
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, name)
|
||||
// The output will consists of one HEADER line and one line of foo/bar-driver
|
||||
c.Assert(len(strings.Split(strings.TrimSpace(out), "\n")), checker.Equals, 2)
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginInspect(c *check.C) {
|
||||
pNameWithTag := ps.getPluginRepoWithTag()
|
||||
|
||||
_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err := dockerCmdWithError("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, pNameWithTag)
|
||||
c.Assert(out, checker.Contains, "true")
|
||||
|
||||
// Find the ID first
|
||||
out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(id, checker.Not(checker.Equals), "")
|
||||
|
||||
// Long form
|
||||
out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", id)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, id)
|
||||
|
||||
// Short form
|
||||
out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", id[:5])
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, id)
|
||||
|
||||
// Name with tag form
|
||||
out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, id)
|
||||
|
||||
// Name without tag form
|
||||
out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", ps.getPluginRepo())
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, id)
|
||||
|
||||
_, _, err = dockerCmdWithError("plugin", "disable", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, pNameWithTag)
|
||||
|
||||
// After remove nothing should be found
|
||||
_, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", id[:5])
|
||||
c.Assert(err, checker.NotNil)
|
||||
}
|
||||
|
||||
// Test case for https://github.com/docker/docker/pull/29186#discussion_r91277345
|
||||
func (s *DockerSuite) TestPluginInspectOnWindows(c *check.C) {
|
||||
// This test should work on Windows only
|
||||
testRequires(c, DaemonIsWindows)
|
||||
|
||||
out, _, err := dockerCmdWithError("plugin", "inspect", "foobar")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "plugins are not supported on this platform")
|
||||
c.Assert(err.Error(), checker.Contains, "plugins are not supported on this platform")
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginIDPrefix(c *check.C) {
|
||||
name := "test"
|
||||
client := testEnv.APIClient()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
initialValue := "0"
|
||||
err := plugin.Create(ctx, client, name, func(cfg *plugin.Config) {
|
||||
cfg.Env = []types.PluginEnv{{Name: "DEBUG", Value: &initialValue, Settable: []string{"value"}}}
|
||||
})
|
||||
cancel()
|
||||
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to create test plugin"))
|
||||
|
||||
// Find ID first
|
||||
id, _, err := dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", name)
|
||||
id = strings.TrimSpace(id)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// List current state
|
||||
out, _, err := dockerCmdWithError("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, name)
|
||||
c.Assert(out, checker.Contains, "false")
|
||||
|
||||
env, _ := dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", id[:5])
|
||||
c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=0]")
|
||||
|
||||
dockerCmd(c, "plugin", "set", id[:5], "DEBUG=1")
|
||||
|
||||
env, _ = dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", id[:5])
|
||||
c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=1]")
|
||||
|
||||
// Enable
|
||||
_, _, err = dockerCmdWithError("plugin", "enable", id[:5])
|
||||
c.Assert(err, checker.IsNil)
|
||||
out, _, err = dockerCmdWithError("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, name)
|
||||
c.Assert(out, checker.Contains, "true")
|
||||
|
||||
// Disable
|
||||
_, _, err = dockerCmdWithError("plugin", "disable", id[:5])
|
||||
c.Assert(err, checker.IsNil)
|
||||
out, _, err = dockerCmdWithError("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, name)
|
||||
c.Assert(out, checker.Contains, "false")
|
||||
|
||||
// Remove
|
||||
_, _, err = dockerCmdWithError("plugin", "remove", id[:5])
|
||||
c.Assert(err, checker.IsNil)
|
||||
// List returns none
|
||||
out, _, err = dockerCmdWithError("plugin", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Not(checker.Contains), name)
|
||||
}
|
||||
|
||||
func (ps *DockerPluginSuite) TestPluginListDefaultFormat(c *check.C) {
|
||||
config, err := ioutil.TempDir("", "config-file-")
|
||||
c.Assert(err, check.IsNil)
|
||||
defer os.RemoveAll(config)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(config, "config.json"), []byte(`{"pluginsFormat": "raw"}`), 0644)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
name := "test:latest"
|
||||
client := testEnv.APIClient()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
err = plugin.Create(ctx, client, name, func(cfg *plugin.Config) {
|
||||
cfg.Description = "test plugin"
|
||||
})
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to create test plugin"))
|
||||
|
||||
out, _ := dockerCmd(c, "plugin", "inspect", "--format", "{{.ID}}", name)
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
// We expect the format to be in `raw + --no-trunc`
|
||||
expectedOutput := fmt.Sprintf(`plugin_id: %s
|
||||
name: %s
|
||||
description: test plugin
|
||||
enabled: false`, id, name)
|
||||
|
||||
out, _ = dockerCmd(c, "--config", config, "plugin", "ls", "--no-trunc")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, expectedOutput)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPluginUpgrade(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, Network, SameHostDaemon, IsAmd64, NotUserNamespace)
|
||||
plugin := "cpuguy83/docker-volume-driver-plugin-local:latest"
|
||||
pluginV2 := "cpuguy83/docker-volume-driver-plugin-local:v2"
|
||||
|
||||
dockerCmd(c, "plugin", "install", "--grant-all-permissions", plugin)
|
||||
dockerCmd(c, "volume", "create", "--driver", plugin, "bananas")
|
||||
dockerCmd(c, "run", "--rm", "-v", "bananas:/apple", "busybox", "sh", "-c", "touch /apple/core")
|
||||
|
||||
out, _, err := dockerCmdWithError("plugin", "upgrade", "--grant-all-permissions", plugin, pluginV2)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "disabled before upgrading")
|
||||
|
||||
out, _ = dockerCmd(c, "plugin", "inspect", "--format={{.ID}}", plugin)
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
// make sure "v2" does not exists
|
||||
_, err = os.Stat(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "plugins", id, "rootfs", "v2"))
|
||||
c.Assert(os.IsNotExist(err), checker.True, check.Commentf("%s", out))
|
||||
|
||||
dockerCmd(c, "plugin", "disable", "-f", plugin)
|
||||
dockerCmd(c, "plugin", "upgrade", "--grant-all-permissions", "--skip-remote-check", plugin, pluginV2)
|
||||
|
||||
// make sure "v2" file exists
|
||||
_, err = os.Stat(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "plugins", id, "rootfs", "v2"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "plugin", "enable", plugin)
|
||||
dockerCmd(c, "volume", "inspect", "bananas")
|
||||
dockerCmd(c, "run", "--rm", "-v", "bananas:/apple", "busybox", "sh", "-c", "ls -lh /apple/core")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPluginMetricsCollector(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, Network, SameHostDaemon, IsAmd64)
|
||||
d := daemon.New(c, dockerBinary, dockerdBinary)
|
||||
d.Start(c)
|
||||
defer d.Stop(c)
|
||||
|
||||
name := "cpuguy83/docker-metrics-plugin-test:latest"
|
||||
r := cli.Docker(cli.Args("plugin", "install", "--grant-all-permissions", name), cli.Daemon(d))
|
||||
c.Assert(r.Error, checker.IsNil, check.Commentf(r.Combined()))
|
||||
|
||||
// plugin lisens on localhost:19393 and proxies the metrics
|
||||
resp, err := http.Get("http://localhost:19393/metrics")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
// check that a known metric is there... don't expect this metric to change over time.. probably safe
|
||||
c.Assert(string(b), checker.Contains, "container_actions")
|
||||
}
|
351
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_port_test.go
generated
vendored
Normal file
351
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_port_test.go
generated
vendored
Normal file
|
@ -0,0 +1,351 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestPortList(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// one port
|
||||
out, _ := dockerCmd(c, "run", "-d", "-p", "9876:80", "busybox", "top")
|
||||
firstID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "port", firstID, "80")
|
||||
|
||||
err := assertPortList(c, out, []string{"0.0.0.0:9876"})
|
||||
// Port list is not correct
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "port", firstID)
|
||||
|
||||
err = assertPortList(c, out, []string{"80/tcp -> 0.0.0.0:9876"})
|
||||
// Port list is not correct
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "rm", "-f", firstID)
|
||||
|
||||
// three port
|
||||
out, _ = dockerCmd(c, "run", "-d",
|
||||
"-p", "9876:80",
|
||||
"-p", "9877:81",
|
||||
"-p", "9878:82",
|
||||
"busybox", "top")
|
||||
ID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "port", ID, "80")
|
||||
|
||||
err = assertPortList(c, out, []string{"0.0.0.0:9876"})
|
||||
// Port list is not correct
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "port", ID)
|
||||
|
||||
err = assertPortList(c, out, []string{
|
||||
"80/tcp -> 0.0.0.0:9876",
|
||||
"81/tcp -> 0.0.0.0:9877",
|
||||
"82/tcp -> 0.0.0.0:9878"})
|
||||
// Port list is not correct
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "rm", "-f", ID)
|
||||
|
||||
// more and one port mapped to the same container port
|
||||
out, _ = dockerCmd(c, "run", "-d",
|
||||
"-p", "9876:80",
|
||||
"-p", "9999:80",
|
||||
"-p", "9877:81",
|
||||
"-p", "9878:82",
|
||||
"busybox", "top")
|
||||
ID = strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "port", ID, "80")
|
||||
|
||||
err = assertPortList(c, out, []string{"0.0.0.0:9876", "0.0.0.0:9999"})
|
||||
// Port list is not correct
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "port", ID)
|
||||
|
||||
err = assertPortList(c, out, []string{
|
||||
"80/tcp -> 0.0.0.0:9876",
|
||||
"80/tcp -> 0.0.0.0:9999",
|
||||
"81/tcp -> 0.0.0.0:9877",
|
||||
"82/tcp -> 0.0.0.0:9878"})
|
||||
// Port list is not correct
|
||||
c.Assert(err, checker.IsNil)
|
||||
dockerCmd(c, "rm", "-f", ID)
|
||||
|
||||
testRange := func() {
|
||||
// host port ranges used
|
||||
IDs := make([]string, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
out, _ = dockerCmd(c, "run", "-d",
|
||||
"-p", "9090-9092:80",
|
||||
"busybox", "top")
|
||||
IDs[i] = strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "port", IDs[i])
|
||||
|
||||
err = assertPortList(c, out, []string{fmt.Sprintf("80/tcp -> 0.0.0.0:%d", 9090+i)})
|
||||
// Port list is not correct
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// test port range exhaustion
|
||||
out, _, err = dockerCmdWithError("run", "-d",
|
||||
"-p", "9090-9092:80",
|
||||
"busybox", "top")
|
||||
// Exhausted port range did not return an error
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
dockerCmd(c, "rm", "-f", IDs[i])
|
||||
}
|
||||
}
|
||||
testRange()
|
||||
// Verify we ran re-use port ranges after they are no longer in use.
|
||||
testRange()
|
||||
|
||||
// test invalid port ranges
|
||||
for _, invalidRange := range []string{"9090-9089:80", "9090-:80", "-9090:80"} {
|
||||
out, _, err = dockerCmdWithError("run", "-d",
|
||||
"-p", invalidRange,
|
||||
"busybox", "top")
|
||||
// Port range should have returned an error
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
}
|
||||
|
||||
// test host range:container range spec.
|
||||
out, _ = dockerCmd(c, "run", "-d",
|
||||
"-p", "9800-9803:80-83",
|
||||
"busybox", "top")
|
||||
ID = strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "port", ID)
|
||||
|
||||
err = assertPortList(c, out, []string{
|
||||
"80/tcp -> 0.0.0.0:9800",
|
||||
"81/tcp -> 0.0.0.0:9801",
|
||||
"82/tcp -> 0.0.0.0:9802",
|
||||
"83/tcp -> 0.0.0.0:9803"})
|
||||
// Port list is not correct
|
||||
c.Assert(err, checker.IsNil)
|
||||
dockerCmd(c, "rm", "-f", ID)
|
||||
|
||||
// test mixing protocols in same port range
|
||||
out, _ = dockerCmd(c, "run", "-d",
|
||||
"-p", "8000-8080:80",
|
||||
"-p", "8000-8080:80/udp",
|
||||
"busybox", "top")
|
||||
ID = strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "port", ID)
|
||||
|
||||
// Running this test multiple times causes the TCP port to increment.
|
||||
err = assertPortRange(c, out, []int{8000, 8080}, []int{8000, 8080})
|
||||
// Port list is not correct
|
||||
c.Assert(err, checker.IsNil)
|
||||
dockerCmd(c, "rm", "-f", ID)
|
||||
}
|
||||
|
||||
func assertPortList(c *check.C, out string, expected []string) error {
|
||||
lines := strings.Split(strings.Trim(out, "\n "), "\n")
|
||||
if len(lines) != len(expected) {
|
||||
return fmt.Errorf("different size lists %s, %d, %d", out, len(lines), len(expected))
|
||||
}
|
||||
sort.Strings(lines)
|
||||
sort.Strings(expected)
|
||||
|
||||
for i := 0; i < len(expected); i++ {
|
||||
if lines[i] != expected[i] {
|
||||
return fmt.Errorf("|" + lines[i] + "!=" + expected[i] + "|")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func assertPortRange(c *check.C, out string, expectedTcp, expectedUdp []int) error {
|
||||
lines := strings.Split(strings.Trim(out, "\n "), "\n")
|
||||
|
||||
var validTcp, validUdp bool
|
||||
for _, l := range lines {
|
||||
// 80/tcp -> 0.0.0.0:8015
|
||||
port, err := strconv.Atoi(strings.Split(l, ":")[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.Contains(l, "tcp") && expectedTcp != nil {
|
||||
if port < expectedTcp[0] || port > expectedTcp[1] {
|
||||
return fmt.Errorf("tcp port (%d) not in range expected range %d-%d", port, expectedTcp[0], expectedTcp[1])
|
||||
}
|
||||
validTcp = true
|
||||
}
|
||||
if strings.Contains(l, "udp") && expectedUdp != nil {
|
||||
if port < expectedUdp[0] || port > expectedUdp[1] {
|
||||
return fmt.Errorf("udp port (%d) not in range expected range %d-%d", port, expectedUdp[0], expectedUdp[1])
|
||||
}
|
||||
validUdp = true
|
||||
}
|
||||
}
|
||||
if !validTcp {
|
||||
return fmt.Errorf("tcp port not found")
|
||||
}
|
||||
if !validUdp {
|
||||
return fmt.Errorf("udp port not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopRemoveContainer(id string, c *check.C) {
|
||||
dockerCmd(c, "rm", "-f", id)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUnpublishedPortsInPsOutput(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// Run busybox with command line expose (equivalent to EXPOSE in image's Dockerfile) for the following ports
|
||||
port1 := 80
|
||||
port2 := 443
|
||||
expose1 := fmt.Sprintf("--expose=%d", port1)
|
||||
expose2 := fmt.Sprintf("--expose=%d", port2)
|
||||
dockerCmd(c, "run", "-d", expose1, expose2, "busybox", "sleep", "5")
|
||||
|
||||
// Check docker ps o/p for last created container reports the unpublished ports
|
||||
unpPort1 := fmt.Sprintf("%d/tcp", port1)
|
||||
unpPort2 := fmt.Sprintf("%d/tcp", port2)
|
||||
out, _ := dockerCmd(c, "ps", "-n=1")
|
||||
// Missing unpublished ports in docker ps output
|
||||
c.Assert(out, checker.Contains, unpPort1)
|
||||
// Missing unpublished ports in docker ps output
|
||||
c.Assert(out, checker.Contains, unpPort2)
|
||||
|
||||
// Run the container forcing to publish the exposed ports
|
||||
dockerCmd(c, "run", "-d", "-P", expose1, expose2, "busybox", "sleep", "5")
|
||||
|
||||
// Check docker ps o/p for last created container reports the exposed ports in the port bindings
|
||||
expBndRegx1 := regexp.MustCompile(`0.0.0.0:\d\d\d\d\d->` + unpPort1)
|
||||
expBndRegx2 := regexp.MustCompile(`0.0.0.0:\d\d\d\d\d->` + unpPort2)
|
||||
out, _ = dockerCmd(c, "ps", "-n=1")
|
||||
// Cannot find expected port binding port (0.0.0.0:xxxxx->unpPort1) in docker ps output
|
||||
c.Assert(expBndRegx1.MatchString(out), checker.Equals, true, check.Commentf("out: %s; unpPort1: %s", out, unpPort1))
|
||||
// Cannot find expected port binding port (0.0.0.0:xxxxx->unpPort2) in docker ps output
|
||||
c.Assert(expBndRegx2.MatchString(out), checker.Equals, true, check.Commentf("out: %s; unpPort2: %s", out, unpPort2))
|
||||
|
||||
// Run the container specifying explicit port bindings for the exposed ports
|
||||
offset := 10000
|
||||
pFlag1 := fmt.Sprintf("%d:%d", offset+port1, port1)
|
||||
pFlag2 := fmt.Sprintf("%d:%d", offset+port2, port2)
|
||||
out, _ = dockerCmd(c, "run", "-d", "-p", pFlag1, "-p", pFlag2, expose1, expose2, "busybox", "sleep", "5")
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
// Check docker ps o/p for last created container reports the specified port mappings
|
||||
expBnd1 := fmt.Sprintf("0.0.0.0:%d->%s", offset+port1, unpPort1)
|
||||
expBnd2 := fmt.Sprintf("0.0.0.0:%d->%s", offset+port2, unpPort2)
|
||||
out, _ = dockerCmd(c, "ps", "-n=1")
|
||||
// Cannot find expected port binding (expBnd1) in docker ps output
|
||||
c.Assert(out, checker.Contains, expBnd1)
|
||||
// Cannot find expected port binding (expBnd2) in docker ps output
|
||||
c.Assert(out, checker.Contains, expBnd2)
|
||||
|
||||
// Remove container now otherwise it will interfere with next test
|
||||
stopRemoveContainer(id, c)
|
||||
|
||||
// Run the container with explicit port bindings and no exposed ports
|
||||
out, _ = dockerCmd(c, "run", "-d", "-p", pFlag1, "-p", pFlag2, "busybox", "sleep", "5")
|
||||
id = strings.TrimSpace(out)
|
||||
|
||||
// Check docker ps o/p for last created container reports the specified port mappings
|
||||
out, _ = dockerCmd(c, "ps", "-n=1")
|
||||
// Cannot find expected port binding (expBnd1) in docker ps output
|
||||
c.Assert(out, checker.Contains, expBnd1)
|
||||
// Cannot find expected port binding (expBnd2) in docker ps output
|
||||
c.Assert(out, checker.Contains, expBnd2)
|
||||
// Remove container now otherwise it will interfere with next test
|
||||
stopRemoveContainer(id, c)
|
||||
|
||||
// Run the container with one unpublished exposed port and one explicit port binding
|
||||
dockerCmd(c, "run", "-d", expose1, "-p", pFlag2, "busybox", "sleep", "5")
|
||||
|
||||
// Check docker ps o/p for last created container reports the specified unpublished port and port mapping
|
||||
out, _ = dockerCmd(c, "ps", "-n=1")
|
||||
// Missing unpublished exposed ports (unpPort1) in docker ps output
|
||||
c.Assert(out, checker.Contains, unpPort1)
|
||||
// Missing port binding (expBnd2) in docker ps output
|
||||
c.Assert(out, checker.Contains, expBnd2)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPortHostBinding(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
out, _ := dockerCmd(c, "run", "-d", "-p", "9876:80", "busybox",
|
||||
"nc", "-l", "-p", "80")
|
||||
firstID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "port", firstID, "80")
|
||||
|
||||
err := assertPortList(c, out, []string{"0.0.0.0:9876"})
|
||||
// Port list is not correct
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "run", "--net=host", "busybox",
|
||||
"nc", "localhost", "9876")
|
||||
|
||||
dockerCmd(c, "rm", "-f", firstID)
|
||||
|
||||
out, _, err = dockerCmdWithError("run", "--net=host", "busybox", "nc", "localhost", "9876")
|
||||
// Port is still bound after the Container is removed
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPortExposeHostBinding(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
out, _ := dockerCmd(c, "run", "-d", "-P", "--expose", "80", "busybox",
|
||||
"nc", "-l", "-p", "80")
|
||||
firstID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "port", firstID, "80")
|
||||
|
||||
_, exposedPort, err := net.SplitHostPort(out)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("out: %s", out))
|
||||
|
||||
dockerCmd(c, "run", "--net=host", "busybox",
|
||||
"nc", "localhost", strings.TrimSpace(exposedPort))
|
||||
|
||||
dockerCmd(c, "rm", "-f", firstID)
|
||||
|
||||
out, _, err = dockerCmdWithError("run", "--net=host", "busybox",
|
||||
"nc", "localhost", strings.TrimSpace(exposedPort))
|
||||
// Port is still bound after the Container is removed
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPortBindingOnSandbox(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
dockerCmd(c, "network", "create", "--internal", "-d", "bridge", "internal-net")
|
||||
nr := getNetworkResource(c, "internal-net")
|
||||
c.Assert(nr.Internal, checker.Equals, true)
|
||||
|
||||
dockerCmd(c, "run", "--net", "internal-net", "-d", "--name", "c1",
|
||||
"-p", "8080:8080", "busybox", "nc", "-l", "-p", "8080")
|
||||
c.Assert(waitRun("c1"), check.IsNil)
|
||||
|
||||
_, _, err := dockerCmdWithError("run", "--net=host", "busybox", "nc", "localhost", "8080")
|
||||
c.Assert(err, check.NotNil,
|
||||
check.Commentf("Port mapping on internal network is expected to fail"))
|
||||
|
||||
// Connect container to another normal bridge network
|
||||
dockerCmd(c, "network", "create", "-d", "bridge", "foo-net")
|
||||
dockerCmd(c, "network", "connect", "foo-net", "c1")
|
||||
|
||||
_, _, err = dockerCmdWithError("run", "--net=host", "busybox", "nc", "localhost", "8080")
|
||||
c.Assert(err, check.IsNil,
|
||||
check.Commentf("Port mapping on the new network is expected to succeed"))
|
||||
|
||||
}
|
51
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_proxy_test.go
generated
vendored
Normal file
51
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_proxy_test.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestCLIProxyDisableProxyUnixSock(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "info"},
|
||||
Env: appendBaseEnv(false, "HTTP_PROXY=http://127.0.0.1:9999"),
|
||||
}).Assert(c, icmd.Success)
|
||||
}
|
||||
|
||||
// Can't use localhost here since go has a special case to not use proxy if connecting to localhost
|
||||
// See https://golang.org/pkg/net/http/#ProxyFromEnvironment
|
||||
func (s *DockerDaemonSuite) TestCLIProxyProxyTCPSock(c *check.C) {
|
||||
testRequires(c, SameHostDaemon)
|
||||
// get the IP to use to connect since we can't use localhost
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
c.Assert(err, checker.IsNil)
|
||||
var ip string
|
||||
for _, addr := range addrs {
|
||||
sAddr := addr.String()
|
||||
if !strings.Contains(sAddr, "127.0.0.1") {
|
||||
addrArr := strings.Split(sAddr, "/")
|
||||
ip = addrArr[0]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
c.Assert(ip, checker.Not(checker.Equals), "")
|
||||
|
||||
s.d.Start(c, "-H", "tcp://"+ip+":2375")
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "info"},
|
||||
Env: []string{"DOCKER_HOST=tcp://" + ip + ":2375", "HTTP_PROXY=127.0.0.1:9999"},
|
||||
}).Assert(c, icmd.Expected{Error: "exit status 1", ExitCode: 1})
|
||||
// Test with no_proxy
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "info"},
|
||||
Env: []string{"DOCKER_HOST=tcp://" + ip + ":2375", "HTTP_PROXY=127.0.0.1:9999", "NO_PROXY=" + ip},
|
||||
}).Assert(c, icmd.Success)
|
||||
}
|
309
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_prune_unix_test.go
generated
vendored
Normal file
309
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_prune_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,309 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func pruneNetworkAndVerify(c *check.C, d *daemon.Daemon, kept, pruned []string) {
|
||||
_, err := d.Cmd("network", "prune", "--force")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
for _, s := range kept {
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(*check.C) (interface{}, check.CommentInterface) {
|
||||
out, err := d.Cmd("network", "ls", "--format", "{{.Name}}")
|
||||
c.Assert(err, checker.IsNil)
|
||||
return out, nil
|
||||
}, checker.Contains, s)
|
||||
}
|
||||
|
||||
for _, s := range pruned {
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(*check.C) (interface{}, check.CommentInterface) {
|
||||
out, err := d.Cmd("network", "ls", "--format", "{{.Name}}")
|
||||
c.Assert(err, checker.IsNil)
|
||||
return out, nil
|
||||
}, checker.Not(checker.Contains), s)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestPruneNetwork(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
_, err := d.Cmd("network", "create", "n1") // used by container (testprune)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = d.Cmd("network", "create", "n2")
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = d.Cmd("network", "create", "n3", "--driver", "overlay") // used by service (testprunesvc)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = d.Cmd("network", "create", "n4", "--driver", "overlay")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
cName := "testprune"
|
||||
_, err = d.Cmd("run", "-d", "--name", cName, "--net", "n1", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
serviceName := "testprunesvc"
|
||||
replicas := 1
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image",
|
||||
"--name", serviceName,
|
||||
"--replicas", strconv.Itoa(replicas),
|
||||
"--network", "n3",
|
||||
"busybox", "top")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, replicas+1)
|
||||
|
||||
// prune and verify
|
||||
pruneNetworkAndVerify(c, d, []string{"n1", "n3"}, []string{"n2", "n4"})
|
||||
|
||||
// remove containers, then prune and verify again
|
||||
_, err = d.Cmd("rm", "-f", cName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = d.Cmd("service", "rm", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 0)
|
||||
|
||||
pruneNetworkAndVerify(c, d, []string{}, []string{"n1", "n3"})
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestPruneImageDangling(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
|
||||
result := cli.BuildCmd(c, "test", cli.Daemon(s.d),
|
||||
build.WithDockerfile(`FROM busybox
|
||||
LABEL foo=bar`),
|
||||
cli.WithFlags("-q"),
|
||||
)
|
||||
result.Assert(c, icmd.Success)
|
||||
id := strings.TrimSpace(result.Combined())
|
||||
|
||||
out, err := s.d.Cmd("images", "-q", "--no-trunc")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id)
|
||||
|
||||
out, err = s.d.Cmd("image", "prune", "--force")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id)
|
||||
|
||||
out, err = s.d.Cmd("images", "-q", "--no-trunc")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id)
|
||||
|
||||
out, err = s.d.Cmd("image", "prune", "--force", "--all")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id)
|
||||
|
||||
out, err = s.d.Cmd("images", "-q", "--no-trunc")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPruneContainerUntil(c *check.C) {
|
||||
out := cli.DockerCmd(c, "run", "-d", "busybox").Combined()
|
||||
id1 := strings.TrimSpace(out)
|
||||
cli.WaitExited(c, id1, 5*time.Second)
|
||||
|
||||
until := daemonUnixTime(c)
|
||||
|
||||
out = cli.DockerCmd(c, "run", "-d", "busybox").Combined()
|
||||
id2 := strings.TrimSpace(out)
|
||||
cli.WaitExited(c, id2, 5*time.Second)
|
||||
|
||||
out = cli.DockerCmd(c, "container", "prune", "--force", "--filter", "until="+until).Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
|
||||
out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc").Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id2)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPruneContainerLabel(c *check.C) {
|
||||
out := cli.DockerCmd(c, "run", "-d", "--label", "foo", "busybox").Combined()
|
||||
id1 := strings.TrimSpace(out)
|
||||
cli.WaitExited(c, id1, 5*time.Second)
|
||||
|
||||
out = cli.DockerCmd(c, "run", "-d", "--label", "bar", "busybox").Combined()
|
||||
id2 := strings.TrimSpace(out)
|
||||
cli.WaitExited(c, id2, 5*time.Second)
|
||||
|
||||
out = cli.DockerCmd(c, "run", "-d", "busybox").Combined()
|
||||
id3 := strings.TrimSpace(out)
|
||||
cli.WaitExited(c, id3, 5*time.Second)
|
||||
|
||||
out = cli.DockerCmd(c, "run", "-d", "--label", "foobar", "busybox").Combined()
|
||||
id4 := strings.TrimSpace(out)
|
||||
cli.WaitExited(c, id4, 5*time.Second)
|
||||
|
||||
// Add a config file of label=foobar, that will have no impact if cli is label!=foobar
|
||||
config := `{"pruneFilters": ["label=foobar"]}`
|
||||
d, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(d)
|
||||
err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// With config.json only, prune based on label=foobar
|
||||
out = cli.DockerCmd(c, "--config", d, "container", "prune", "--force").Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id3)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id4)
|
||||
|
||||
out = cli.DockerCmd(c, "container", "prune", "--force", "--filter", "label=foo").Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id3)
|
||||
|
||||
out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc").Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id2)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id3)
|
||||
|
||||
out = cli.DockerCmd(c, "container", "prune", "--force", "--filter", "label!=bar").Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id3)
|
||||
|
||||
out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc").Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id2)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id3)
|
||||
|
||||
// With config.json label=foobar and CLI label!=foobar, CLI label!=foobar supersede
|
||||
out = cli.DockerCmd(c, "--config", d, "container", "prune", "--force", "--filter", "label!=foobar").Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id2)
|
||||
|
||||
out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc").Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPruneVolumeLabel(c *check.C) {
|
||||
out, _ := dockerCmd(c, "volume", "create", "--label", "foo")
|
||||
id1 := strings.TrimSpace(out)
|
||||
c.Assert(id1, checker.Not(checker.Equals), "")
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "create", "--label", "bar")
|
||||
id2 := strings.TrimSpace(out)
|
||||
c.Assert(id2, checker.Not(checker.Equals), "")
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "create")
|
||||
id3 := strings.TrimSpace(out)
|
||||
c.Assert(id3, checker.Not(checker.Equals), "")
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "create", "--label", "foobar")
|
||||
id4 := strings.TrimSpace(out)
|
||||
c.Assert(id4, checker.Not(checker.Equals), "")
|
||||
|
||||
// Add a config file of label=foobar, that will have no impact if cli is label!=foobar
|
||||
config := `{"pruneFilters": ["label=foobar"]}`
|
||||
d, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(d)
|
||||
err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// With config.json only, prune based on label=foobar
|
||||
out, _ = dockerCmd(c, "--config", d, "volume", "prune", "--force")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id3)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id4)
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "prune", "--force", "--filter", "label=foo")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id3)
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--format", "{{.Name}}")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id2)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id3)
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "prune", "--force", "--filter", "label!=bar")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id3)
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--format", "{{.Name}}")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id2)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id3)
|
||||
|
||||
// With config.json label=foobar and CLI label!=foobar, CLI label!=foobar supersede
|
||||
out, _ = dockerCmd(c, "--config", d, "volume", "prune", "--force", "--filter", "label!=foobar")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id2)
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--format", "{{.Name}}")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPruneNetworkLabel(c *check.C) {
|
||||
dockerCmd(c, "network", "create", "--label", "foo", "n1")
|
||||
dockerCmd(c, "network", "create", "--label", "bar", "n2")
|
||||
dockerCmd(c, "network", "create", "n3")
|
||||
|
||||
out, _ := dockerCmd(c, "network", "prune", "--force", "--filter", "label=foo")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "n1")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), "n2")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), "n3")
|
||||
|
||||
out, _ = dockerCmd(c, "network", "prune", "--force", "--filter", "label!=bar")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), "n1")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), "n2")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "n3")
|
||||
|
||||
out, _ = dockerCmd(c, "network", "prune", "--force")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), "n1")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "n2")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), "n3")
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestPruneImageLabel(c *check.C) {
|
||||
s.d.StartWithBusybox(c)
|
||||
|
||||
result := cli.BuildCmd(c, "test1", cli.Daemon(s.d),
|
||||
build.WithDockerfile(`FROM busybox
|
||||
LABEL foo=bar`),
|
||||
cli.WithFlags("-q"),
|
||||
)
|
||||
result.Assert(c, icmd.Success)
|
||||
id1 := strings.TrimSpace(result.Combined())
|
||||
out, err := s.d.Cmd("images", "-q", "--no-trunc")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id1)
|
||||
|
||||
result = cli.BuildCmd(c, "test2", cli.Daemon(s.d),
|
||||
build.WithDockerfile(`FROM busybox
|
||||
LABEL bar=foo`),
|
||||
cli.WithFlags("-q"),
|
||||
)
|
||||
result.Assert(c, icmd.Success)
|
||||
id2 := strings.TrimSpace(result.Combined())
|
||||
out, err = s.d.Cmd("images", "-q", "--no-trunc")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id2)
|
||||
|
||||
out, err = s.d.Cmd("image", "prune", "--force", "--all", "--filter", "label=foo=bar")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
|
||||
out, err = s.d.Cmd("image", "prune", "--force", "--all", "--filter", "label!=bar=foo")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id2)
|
||||
|
||||
out, err = s.d.Cmd("image", "prune", "--force", "--all", "--filter", "label=bar=foo")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id2)
|
||||
}
|
869
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_ps_test.go
generated
vendored
Normal file
869
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_ps_test.go
generated
vendored
Normal file
|
@ -0,0 +1,869 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersBase(c *check.C) {
|
||||
existingContainers := ExistingContainerIDs(c)
|
||||
|
||||
out := runSleepingContainer(c, "-d")
|
||||
firstID := strings.TrimSpace(out)
|
||||
|
||||
out = runSleepingContainer(c, "-d")
|
||||
secondID := strings.TrimSpace(out)
|
||||
|
||||
// not long running
|
||||
out, _ = dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
thirdID := strings.TrimSpace(out)
|
||||
|
||||
out = runSleepingContainer(c, "-d")
|
||||
fourthID := strings.TrimSpace(out)
|
||||
|
||||
// make sure the second is running
|
||||
c.Assert(waitRun(secondID), checker.IsNil)
|
||||
|
||||
// make sure third one is not running
|
||||
dockerCmd(c, "wait", thirdID)
|
||||
|
||||
// make sure the forth is running
|
||||
c.Assert(waitRun(fourthID), checker.IsNil)
|
||||
|
||||
// all
|
||||
out, _ = dockerCmd(c, "ps", "-a")
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), []string{fourthID, thirdID, secondID, firstID}), checker.Equals, true, check.Commentf("ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// running
|
||||
out, _ = dockerCmd(c, "ps")
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), []string{fourthID, secondID, firstID}), checker.Equals, true, check.Commentf("RUNNING: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// limit
|
||||
out, _ = dockerCmd(c, "ps", "-n=2", "-a")
|
||||
expected := []string{fourthID, thirdID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("LIMIT & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-n=2")
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("LIMIT: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter since
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-a")
|
||||
expected = []string{fourthID, thirdID, secondID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("SINCE filter & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID)
|
||||
expected = []string{fourthID, secondID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("SINCE filter: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+thirdID)
|
||||
expected = []string{fourthID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("SINCE filter: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter before
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-a")
|
||||
expected = []string{thirdID, secondID, firstID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("BEFORE filter & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID)
|
||||
expected = []string{secondID, firstID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("BEFORE filter: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+thirdID)
|
||||
expected = []string{secondID, firstID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("SINCE filter: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter since & before
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-a")
|
||||
expected = []string{thirdID, secondID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID)
|
||||
expected = []string{secondID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter since & limit
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2", "-a")
|
||||
expected = []string{fourthID, thirdID}
|
||||
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("SINCE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2")
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("SINCE filter, LIMIT: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter before & limit
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1", "-a")
|
||||
expected = []string{thirdID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("BEFORE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1")
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("BEFORE filter, LIMIT: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter since & filter before & limit
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1", "-a")
|
||||
expected = []string{thirdID}
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1")
|
||||
c.Assert(assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter, LIMIT: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
}
|
||||
|
||||
func assertContainerList(out string, expected []string) bool {
|
||||
lines := strings.Split(strings.Trim(out, "\n "), "\n")
|
||||
|
||||
if len(lines)-1 != len(expected) {
|
||||
return false
|
||||
}
|
||||
|
||||
containerIDIndex := strings.Index(lines[0], "CONTAINER ID")
|
||||
for i := 0; i < len(expected); i++ {
|
||||
foundID := lines[i+1][containerIDIndex : containerIDIndex+12]
|
||||
if foundID != expected[i][:12] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersSize(c *check.C) {
|
||||
// Problematic on Windows as it doesn't report the size correctly @swernli
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "busybox")
|
||||
|
||||
baseOut, _ := dockerCmd(c, "ps", "-s", "-n=1")
|
||||
baseLines := strings.Split(strings.Trim(baseOut, "\n "), "\n")
|
||||
baseSizeIndex := strings.Index(baseLines[0], "SIZE")
|
||||
baseFoundsize := baseLines[1][baseSizeIndex:]
|
||||
baseBytes, err := strconv.Atoi(strings.Split(baseFoundsize, "B")[0])
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
name := "test_size"
|
||||
dockerCmd(c, "run", "--name", name, "busybox", "sh", "-c", "echo 1 > test")
|
||||
id := getIDByName(c, name)
|
||||
|
||||
var result *icmd.Result
|
||||
|
||||
wait := make(chan struct{})
|
||||
go func() {
|
||||
result = icmd.RunCommand(dockerBinary, "ps", "-s", "-n=1")
|
||||
close(wait)
|
||||
}()
|
||||
select {
|
||||
case <-wait:
|
||||
case <-time.After(3 * time.Second):
|
||||
c.Fatalf("Calling \"docker ps -s\" timed out!")
|
||||
}
|
||||
result.Assert(c, icmd.Success)
|
||||
lines := strings.Split(strings.Trim(result.Combined(), "\n "), "\n")
|
||||
c.Assert(lines, checker.HasLen, 2, check.Commentf("Expected 2 lines for 'ps -s -n=1' output, got %d", len(lines)))
|
||||
sizeIndex := strings.Index(lines[0], "SIZE")
|
||||
idIndex := strings.Index(lines[0], "CONTAINER ID")
|
||||
foundID := lines[1][idIndex : idIndex+12]
|
||||
c.Assert(foundID, checker.Equals, id[:12], check.Commentf("Expected id %s, got %s", id[:12], foundID))
|
||||
expectedSize := fmt.Sprintf("%dB", 2+baseBytes)
|
||||
foundSize := lines[1][sizeIndex:]
|
||||
c.Assert(foundSize, checker.Contains, expectedSize, check.Commentf("Expected size %q, got %q", expectedSize, foundSize))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersFilterStatus(c *check.C) {
|
||||
existingContainers := ExistingContainerIDs(c)
|
||||
|
||||
// start exited container
|
||||
out := cli.DockerCmd(c, "run", "-d", "busybox").Combined()
|
||||
firstID := strings.TrimSpace(out)
|
||||
|
||||
// make sure the exited container is not running
|
||||
cli.DockerCmd(c, "wait", firstID)
|
||||
|
||||
// start running container
|
||||
out = cli.DockerCmd(c, "run", "-itd", "busybox").Combined()
|
||||
secondID := strings.TrimSpace(out)
|
||||
|
||||
// filter containers by exited
|
||||
out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter=status=exited").Combined()
|
||||
containerOut := strings.TrimSpace(out)
|
||||
c.Assert(RemoveOutputForExistingElements(containerOut, existingContainers), checker.Equals, firstID)
|
||||
|
||||
out = cli.DockerCmd(c, "ps", "-a", "--no-trunc", "-q", "--filter=status=running").Combined()
|
||||
containerOut = strings.TrimSpace(out)
|
||||
c.Assert(RemoveOutputForExistingElements(containerOut, existingContainers), checker.Equals, secondID)
|
||||
|
||||
result := cli.Docker(cli.Args("ps", "-a", "-q", "--filter=status=rubbish"), cli.WithTimeout(time.Second*60))
|
||||
err := "Invalid filter 'status=rubbish'"
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
err = "Unrecognised filter value for status: rubbish"
|
||||
}
|
||||
result.Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: err,
|
||||
})
|
||||
// Windows doesn't support pausing of containers
|
||||
if testEnv.OSType != "windows" {
|
||||
// pause running container
|
||||
out = cli.DockerCmd(c, "run", "-itd", "busybox").Combined()
|
||||
pausedID := strings.TrimSpace(out)
|
||||
cli.DockerCmd(c, "pause", pausedID)
|
||||
// make sure the container is unpaused to let the daemon stop it properly
|
||||
defer func() { cli.DockerCmd(c, "unpause", pausedID) }()
|
||||
|
||||
out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter=status=paused").Combined()
|
||||
containerOut = strings.TrimSpace(out)
|
||||
c.Assert(RemoveOutputForExistingElements(containerOut, existingContainers), checker.Equals, pausedID)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersFilterHealth(c *check.C) {
|
||||
existingContainers := ExistingContainerIDs(c)
|
||||
// Test legacy no health check
|
||||
out := runSleepingContainer(c, "--name=none_legacy")
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
cli.WaitRun(c, containerID)
|
||||
|
||||
out = cli.DockerCmd(c, "ps", "-q", "-l", "--no-trunc", "--filter=health=none").Combined()
|
||||
containerOut := strings.TrimSpace(out)
|
||||
c.Assert(containerOut, checker.Equals, containerID, check.Commentf("Expected id %s, got %s for legacy none filter, output: %q", containerID, containerOut, out))
|
||||
|
||||
// Test no health check specified explicitly
|
||||
out = runSleepingContainer(c, "--name=none", "--no-healthcheck")
|
||||
containerID = strings.TrimSpace(out)
|
||||
|
||||
cli.WaitRun(c, containerID)
|
||||
|
||||
out = cli.DockerCmd(c, "ps", "-q", "-l", "--no-trunc", "--filter=health=none").Combined()
|
||||
containerOut = strings.TrimSpace(out)
|
||||
c.Assert(containerOut, checker.Equals, containerID, check.Commentf("Expected id %s, got %s for none filter, output: %q", containerID, containerOut, out))
|
||||
|
||||
// Test failing health check
|
||||
out = runSleepingContainer(c, "--name=failing_container", "--health-cmd=exit 1", "--health-interval=1s")
|
||||
containerID = strings.TrimSpace(out)
|
||||
|
||||
waitForHealthStatus(c, "failing_container", "starting", "unhealthy")
|
||||
|
||||
out = cli.DockerCmd(c, "ps", "-q", "--no-trunc", "--filter=health=unhealthy").Combined()
|
||||
containerOut = strings.TrimSpace(out)
|
||||
c.Assert(containerOut, checker.Equals, containerID, check.Commentf("Expected containerID %s, got %s for unhealthy filter, output: %q", containerID, containerOut, out))
|
||||
|
||||
// Check passing healthcheck
|
||||
out = runSleepingContainer(c, "--name=passing_container", "--health-cmd=exit 0", "--health-interval=1s")
|
||||
containerID = strings.TrimSpace(out)
|
||||
|
||||
waitForHealthStatus(c, "passing_container", "starting", "healthy")
|
||||
|
||||
out = cli.DockerCmd(c, "ps", "-q", "--no-trunc", "--filter=health=healthy").Combined()
|
||||
containerOut = strings.TrimSpace(RemoveOutputForExistingElements(out, existingContainers))
|
||||
c.Assert(containerOut, checker.Equals, containerID, check.Commentf("Expected containerID %s, got %s for healthy filter, output: %q", containerID, containerOut, out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersFilterID(c *check.C) {
|
||||
// start container
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox")
|
||||
firstID := strings.TrimSpace(out)
|
||||
|
||||
// start another container
|
||||
runSleepingContainer(c)
|
||||
|
||||
// filter containers by id
|
||||
out, _ = dockerCmd(c, "ps", "-a", "-q", "--filter=id="+firstID)
|
||||
containerOut := strings.TrimSpace(out)
|
||||
c.Assert(containerOut, checker.Equals, firstID[:12], check.Commentf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersFilterName(c *check.C) {
|
||||
// start container
|
||||
dockerCmd(c, "run", "--name=a_name_to_match", "busybox")
|
||||
id := getIDByName(c, "a_name_to_match")
|
||||
|
||||
// start another container
|
||||
runSleepingContainer(c, "--name=b_name_to_match")
|
||||
|
||||
// filter containers by name
|
||||
out, _ := dockerCmd(c, "ps", "-a", "-q", "--filter=name=a_name_to_match")
|
||||
containerOut := strings.TrimSpace(out)
|
||||
c.Assert(containerOut, checker.Equals, id[:12], check.Commentf("Expected id %s, got %s for exited filter, output: %q", id[:12], containerOut, out))
|
||||
}
|
||||
|
||||
// Test for the ancestor filter for ps.
|
||||
// There is also the same test but with image:tag@digest in docker_cli_by_digest_test.go
|
||||
//
|
||||
// What the test setups :
|
||||
// - Create 2 image based on busybox using the same repository but different tags
|
||||
// - Create an image based on the previous image (images_ps_filter_test2)
|
||||
// - Run containers for each of those image (busybox, images_ps_filter_test1, images_ps_filter_test2)
|
||||
// - Filter them out :P
|
||||
func (s *DockerSuite) TestPsListContainersFilterAncestorImage(c *check.C) {
|
||||
existingContainers := ExistingContainerIDs(c)
|
||||
|
||||
// Build images
|
||||
imageName1 := "images_ps_filter_test1"
|
||||
buildImageSuccessfully(c, imageName1, build.WithDockerfile(`FROM busybox
|
||||
LABEL match me 1`))
|
||||
imageID1 := getIDByName(c, imageName1)
|
||||
|
||||
imageName1Tagged := "images_ps_filter_test1:tag"
|
||||
buildImageSuccessfully(c, imageName1Tagged, build.WithDockerfile(`FROM busybox
|
||||
LABEL match me 1 tagged`))
|
||||
imageID1Tagged := getIDByName(c, imageName1Tagged)
|
||||
|
||||
imageName2 := "images_ps_filter_test2"
|
||||
buildImageSuccessfully(c, imageName2, build.WithDockerfile(fmt.Sprintf(`FROM %s
|
||||
LABEL match me 2`, imageName1)))
|
||||
imageID2 := getIDByName(c, imageName2)
|
||||
|
||||
// start containers
|
||||
dockerCmd(c, "run", "--name=first", "busybox", "echo", "hello")
|
||||
firstID := getIDByName(c, "first")
|
||||
|
||||
// start another container
|
||||
dockerCmd(c, "run", "--name=second", "busybox", "echo", "hello")
|
||||
secondID := getIDByName(c, "second")
|
||||
|
||||
// start third container
|
||||
dockerCmd(c, "run", "--name=third", imageName1, "echo", "hello")
|
||||
thirdID := getIDByName(c, "third")
|
||||
|
||||
// start fourth container
|
||||
dockerCmd(c, "run", "--name=fourth", imageName1Tagged, "echo", "hello")
|
||||
fourthID := getIDByName(c, "fourth")
|
||||
|
||||
// start fifth container
|
||||
dockerCmd(c, "run", "--name=fifth", imageName2, "echo", "hello")
|
||||
fifthID := getIDByName(c, "fifth")
|
||||
|
||||
var filterTestSuite = []struct {
|
||||
filterName string
|
||||
expectedIDs []string
|
||||
}{
|
||||
// non existent stuff
|
||||
{"nonexistent", []string{}},
|
||||
{"nonexistent:tag", []string{}},
|
||||
// image
|
||||
{"busybox", []string{firstID, secondID, thirdID, fourthID, fifthID}},
|
||||
{imageName1, []string{thirdID, fifthID}},
|
||||
{imageName2, []string{fifthID}},
|
||||
// image:tag
|
||||
{fmt.Sprintf("%s:latest", imageName1), []string{thirdID, fifthID}},
|
||||
{imageName1Tagged, []string{fourthID}},
|
||||
// short-id
|
||||
{stringid.TruncateID(imageID1), []string{thirdID, fifthID}},
|
||||
{stringid.TruncateID(imageID2), []string{fifthID}},
|
||||
// full-id
|
||||
{imageID1, []string{thirdID, fifthID}},
|
||||
{imageID1Tagged, []string{fourthID}},
|
||||
{imageID2, []string{fifthID}},
|
||||
}
|
||||
|
||||
var out string
|
||||
for _, filter := range filterTestSuite {
|
||||
out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=ancestor="+filter.filterName)
|
||||
checkPsAncestorFilterOutput(c, RemoveOutputForExistingElements(out, existingContainers), filter.filterName, filter.expectedIDs)
|
||||
}
|
||||
|
||||
// Multiple ancestor filter
|
||||
out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=ancestor="+imageName2, "--filter=ancestor="+imageName1Tagged)
|
||||
checkPsAncestorFilterOutput(c, RemoveOutputForExistingElements(out, existingContainers), imageName2+","+imageName1Tagged, []string{fourthID, fifthID})
|
||||
}
|
||||
|
||||
func checkPsAncestorFilterOutput(c *check.C, out string, filterName string, expectedIDs []string) {
|
||||
var actualIDs []string
|
||||
if out != "" {
|
||||
actualIDs = strings.Split(out[:len(out)-1], "\n")
|
||||
}
|
||||
sort.Strings(actualIDs)
|
||||
sort.Strings(expectedIDs)
|
||||
|
||||
c.Assert(actualIDs, checker.HasLen, len(expectedIDs), check.Commentf("Expected filtered container(s) for %s ancestor filter to be %v:%v, got %v:%v", filterName, len(expectedIDs), expectedIDs, len(actualIDs), actualIDs))
|
||||
if len(expectedIDs) > 0 {
|
||||
same := true
|
||||
for i := range expectedIDs {
|
||||
if actualIDs[i] != expectedIDs[i] {
|
||||
c.Logf("%s, %s", actualIDs[i], expectedIDs[i])
|
||||
same = false
|
||||
break
|
||||
}
|
||||
}
|
||||
c.Assert(same, checker.Equals, true, check.Commentf("Expected filtered container(s) for %s ancestor filter to be %v, got %v", filterName, expectedIDs, actualIDs))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersFilterLabel(c *check.C) {
|
||||
// start container
|
||||
dockerCmd(c, "run", "--name=first", "-l", "match=me", "-l", "second=tag", "busybox")
|
||||
firstID := getIDByName(c, "first")
|
||||
|
||||
// start another container
|
||||
dockerCmd(c, "run", "--name=second", "-l", "match=me too", "busybox")
|
||||
secondID := getIDByName(c, "second")
|
||||
|
||||
// start third container
|
||||
dockerCmd(c, "run", "--name=third", "-l", "nomatch=me", "busybox")
|
||||
thirdID := getIDByName(c, "third")
|
||||
|
||||
// filter containers by exact match
|
||||
out, _ := dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me")
|
||||
containerOut := strings.TrimSpace(out)
|
||||
c.Assert(containerOut, checker.Equals, firstID, check.Commentf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out))
|
||||
|
||||
// filter containers by two labels
|
||||
out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me", "--filter=label=second=tag")
|
||||
containerOut = strings.TrimSpace(out)
|
||||
c.Assert(containerOut, checker.Equals, firstID, check.Commentf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out))
|
||||
|
||||
// filter containers by two labels, but expect not found because of AND behavior
|
||||
out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me", "--filter=label=second=tag-no")
|
||||
containerOut = strings.TrimSpace(out)
|
||||
c.Assert(containerOut, checker.Equals, "", check.Commentf("Expected nothing, got %s for exited filter, output: %q", containerOut, out))
|
||||
|
||||
// filter containers by exact key
|
||||
out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match")
|
||||
containerOut = strings.TrimSpace(out)
|
||||
c.Assert(containerOut, checker.Contains, firstID)
|
||||
c.Assert(containerOut, checker.Contains, secondID)
|
||||
c.Assert(containerOut, checker.Not(checker.Contains), thirdID)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersFilterExited(c *check.C) {
|
||||
runSleepingContainer(c, "--name=sleep")
|
||||
|
||||
dockerCmd(c, "run", "--name", "zero1", "busybox", "true")
|
||||
firstZero := getIDByName(c, "zero1")
|
||||
|
||||
dockerCmd(c, "run", "--name", "zero2", "busybox", "true")
|
||||
secondZero := getIDByName(c, "zero2")
|
||||
|
||||
out, _, err := dockerCmdWithError("run", "--name", "nonzero1", "busybox", "false")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("Should fail.", out, err))
|
||||
|
||||
firstNonZero := getIDByName(c, "nonzero1")
|
||||
|
||||
out, _, err = dockerCmdWithError("run", "--name", "nonzero2", "busybox", "false")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("Should fail.", out, err))
|
||||
secondNonZero := getIDByName(c, "nonzero2")
|
||||
|
||||
// filter containers by exited=0
|
||||
out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=exited=0")
|
||||
ids := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(ids, checker.HasLen, 2, check.Commentf("Should be 2 zero exited containers got %d: %s", len(ids), out))
|
||||
c.Assert(ids[0], checker.Equals, secondZero, check.Commentf("First in list should be %q, got %q", secondZero, ids[0]))
|
||||
c.Assert(ids[1], checker.Equals, firstZero, check.Commentf("Second in list should be %q, got %q", firstZero, ids[1]))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=exited=1")
|
||||
ids = strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(ids, checker.HasLen, 2, check.Commentf("Should be 2 zero exited containers got %d", len(ids)))
|
||||
c.Assert(ids[0], checker.Equals, secondNonZero, check.Commentf("First in list should be %q, got %q", secondNonZero, ids[0]))
|
||||
c.Assert(ids[1], checker.Equals, firstNonZero, check.Commentf("Second in list should be %q, got %q", firstNonZero, ids[1]))
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsRightTagName(c *check.C) {
|
||||
// TODO Investigate further why this fails on Windows to Windows CI
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
existingContainers := ExistingContainerNames(c)
|
||||
|
||||
tag := "asybox:shmatest"
|
||||
dockerCmd(c, "tag", "busybox", tag)
|
||||
|
||||
var id1 string
|
||||
out := runSleepingContainer(c)
|
||||
id1 = strings.TrimSpace(string(out))
|
||||
|
||||
var id2 string
|
||||
out = runSleepingContainerInImage(c, tag)
|
||||
id2 = strings.TrimSpace(string(out))
|
||||
|
||||
var imageID string
|
||||
out = inspectField(c, "busybox", "Id")
|
||||
imageID = strings.TrimSpace(string(out))
|
||||
|
||||
var id3 string
|
||||
out = runSleepingContainerInImage(c, imageID)
|
||||
id3 = strings.TrimSpace(string(out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--no-trunc")
|
||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
lines = RemoveLinesForExistingElements(lines, existingContainers)
|
||||
// skip header
|
||||
lines = lines[1:]
|
||||
c.Assert(lines, checker.HasLen, 3, check.Commentf("There should be 3 running container, got %d", len(lines)))
|
||||
for _, line := range lines {
|
||||
f := strings.Fields(line)
|
||||
switch f[0] {
|
||||
case id1:
|
||||
c.Assert(f[1], checker.Equals, "busybox", check.Commentf("Expected %s tag for id %s, got %s", "busybox", id1, f[1]))
|
||||
case id2:
|
||||
c.Assert(f[1], checker.Equals, tag, check.Commentf("Expected %s tag for id %s, got %s", tag, id2, f[1]))
|
||||
case id3:
|
||||
c.Assert(f[1], checker.Equals, imageID, check.Commentf("Expected %s imageID for id %s, got %s", tag, id3, f[1]))
|
||||
default:
|
||||
c.Fatalf("Unexpected id %s, expected %s and %s and %s", f[0], id1, id2, id3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersFilterCreated(c *check.C) {
|
||||
// create a container
|
||||
out, _ := dockerCmd(c, "create", "busybox")
|
||||
cID := strings.TrimSpace(out)
|
||||
shortCID := cID[:12]
|
||||
|
||||
// Make sure it DOESN'T show up w/o a '-a' for normal 'ps'
|
||||
out, _ = dockerCmd(c, "ps", "-q")
|
||||
c.Assert(out, checker.Not(checker.Contains), shortCID, check.Commentf("Should have not seen '%s' in ps output:\n%s", shortCID, out))
|
||||
|
||||
// Make sure it DOES show up as 'Created' for 'ps -a'
|
||||
out, _ = dockerCmd(c, "ps", "-a")
|
||||
|
||||
hits := 0
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
if !strings.Contains(line, shortCID) {
|
||||
continue
|
||||
}
|
||||
hits++
|
||||
c.Assert(line, checker.Contains, "Created", check.Commentf("Missing 'Created' on '%s'", line))
|
||||
}
|
||||
|
||||
c.Assert(hits, checker.Equals, 1, check.Commentf("Should have seen '%s' in ps -a output once:%d\n%s", shortCID, hits, out))
|
||||
|
||||
// filter containers by 'create' - note, no -a needed
|
||||
out, _ = dockerCmd(c, "ps", "-q", "-f", "status=created")
|
||||
containerOut := strings.TrimSpace(out)
|
||||
c.Assert(cID, checker.HasPrefix, containerOut)
|
||||
}
|
||||
|
||||
// Test for GitHub issue #12595
|
||||
func (s *DockerSuite) TestPsImageIDAfterUpdate(c *check.C) {
|
||||
// TODO: Investigate why this fails on Windows to Windows CI further.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
originalImageName := "busybox:TestPsImageIDAfterUpdate-original"
|
||||
updatedImageName := "busybox:TestPsImageIDAfterUpdate-updated"
|
||||
|
||||
existingContainers := ExistingContainerIDs(c)
|
||||
|
||||
icmd.RunCommand(dockerBinary, "tag", "busybox:latest", originalImageName).Assert(c, icmd.Success)
|
||||
|
||||
originalImageID := getIDByName(c, originalImageName)
|
||||
|
||||
result := icmd.RunCommand(dockerBinary, append([]string{"run", "-d", originalImageName}, sleepCommandForDaemonPlatform()...)...)
|
||||
result.Assert(c, icmd.Success)
|
||||
containerID := strings.TrimSpace(result.Combined())
|
||||
|
||||
result = icmd.RunCommand(dockerBinary, "ps", "--no-trunc")
|
||||
result.Assert(c, icmd.Success)
|
||||
|
||||
lines := strings.Split(strings.TrimSpace(string(result.Combined())), "\n")
|
||||
lines = RemoveLinesForExistingElements(lines, existingContainers)
|
||||
// skip header
|
||||
lines = lines[1:]
|
||||
c.Assert(len(lines), checker.Equals, 1)
|
||||
|
||||
for _, line := range lines {
|
||||
f := strings.Fields(line)
|
||||
c.Assert(f[1], checker.Equals, originalImageName)
|
||||
}
|
||||
|
||||
icmd.RunCommand(dockerBinary, "commit", containerID, updatedImageName).Assert(c, icmd.Success)
|
||||
icmd.RunCommand(dockerBinary, "tag", updatedImageName, originalImageName).Assert(c, icmd.Success)
|
||||
|
||||
result = icmd.RunCommand(dockerBinary, "ps", "--no-trunc")
|
||||
result.Assert(c, icmd.Success)
|
||||
|
||||
lines = strings.Split(strings.TrimSpace(string(result.Combined())), "\n")
|
||||
lines = RemoveLinesForExistingElements(lines, existingContainers)
|
||||
// skip header
|
||||
lines = lines[1:]
|
||||
c.Assert(len(lines), checker.Equals, 1)
|
||||
|
||||
for _, line := range lines {
|
||||
f := strings.Fields(line)
|
||||
c.Assert(f[1], checker.Equals, originalImageID)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsNotShowPortsOfStoppedContainer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "--name=foo", "-d", "-p", "5000:5000", "busybox", "top")
|
||||
c.Assert(waitRun("foo"), checker.IsNil)
|
||||
out, _ := dockerCmd(c, "ps")
|
||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
expected := "0.0.0.0:5000->5000/tcp"
|
||||
fields := strings.Fields(lines[1])
|
||||
c.Assert(fields[len(fields)-2], checker.Equals, expected, check.Commentf("Expected: %v, got: %v", expected, fields[len(fields)-2]))
|
||||
|
||||
dockerCmd(c, "kill", "foo")
|
||||
dockerCmd(c, "wait", "foo")
|
||||
out, _ = dockerCmd(c, "ps", "-l")
|
||||
lines = strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
fields = strings.Fields(lines[1])
|
||||
c.Assert(fields[len(fields)-2], checker.Not(checker.Equals), expected, check.Commentf("Should not got %v", expected))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsShowMounts(c *check.C) {
|
||||
existingContainers := ExistingContainerNames(c)
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
|
||||
mp := prefix + slash + "test"
|
||||
|
||||
dockerCmd(c, "volume", "create", "ps-volume-test")
|
||||
// volume mount containers
|
||||
runSleepingContainer(c, "--name=volume-test-1", "--volume", "ps-volume-test:"+mp)
|
||||
c.Assert(waitRun("volume-test-1"), checker.IsNil)
|
||||
runSleepingContainer(c, "--name=volume-test-2", "--volume", mp)
|
||||
c.Assert(waitRun("volume-test-2"), checker.IsNil)
|
||||
// bind mount container
|
||||
var bindMountSource string
|
||||
var bindMountDestination string
|
||||
if DaemonIsWindows() {
|
||||
bindMountSource = "c:\\"
|
||||
bindMountDestination = "c:\\t"
|
||||
} else {
|
||||
bindMountSource = "/tmp"
|
||||
bindMountDestination = "/t"
|
||||
}
|
||||
runSleepingContainer(c, "--name=bind-mount-test", "-v", bindMountSource+":"+bindMountDestination)
|
||||
c.Assert(waitRun("bind-mount-test"), checker.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}")
|
||||
|
||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
lines = RemoveLinesForExistingElements(lines, existingContainers)
|
||||
c.Assert(lines, checker.HasLen, 3)
|
||||
|
||||
fields := strings.Fields(lines[0])
|
||||
c.Assert(fields, checker.HasLen, 2)
|
||||
c.Assert(fields[0], checker.Equals, "bind-mount-test")
|
||||
c.Assert(fields[1], checker.Equals, bindMountSource)
|
||||
|
||||
fields = strings.Fields(lines[1])
|
||||
c.Assert(fields, checker.HasLen, 2)
|
||||
|
||||
anonymousVolumeID := fields[1]
|
||||
|
||||
fields = strings.Fields(lines[2])
|
||||
c.Assert(fields[1], checker.Equals, "ps-volume-test")
|
||||
|
||||
// filter by volume name
|
||||
out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=ps-volume-test")
|
||||
|
||||
lines = strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
lines = RemoveLinesForExistingElements(lines, existingContainers)
|
||||
c.Assert(lines, checker.HasLen, 1)
|
||||
|
||||
fields = strings.Fields(lines[0])
|
||||
c.Assert(fields[1], checker.Equals, "ps-volume-test")
|
||||
|
||||
// empty results filtering by unknown volume
|
||||
out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=this-volume-should-not-exist")
|
||||
c.Assert(strings.TrimSpace(string(out)), checker.HasLen, 0)
|
||||
|
||||
// filter by mount destination
|
||||
out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+mp)
|
||||
|
||||
lines = strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
lines = RemoveLinesForExistingElements(lines, existingContainers)
|
||||
c.Assert(lines, checker.HasLen, 2)
|
||||
|
||||
fields = strings.Fields(lines[0])
|
||||
c.Assert(fields[1], checker.Equals, anonymousVolumeID)
|
||||
fields = strings.Fields(lines[1])
|
||||
c.Assert(fields[1], checker.Equals, "ps-volume-test")
|
||||
|
||||
// filter by bind mount source
|
||||
out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountSource)
|
||||
|
||||
lines = strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
lines = RemoveLinesForExistingElements(lines, existingContainers)
|
||||
c.Assert(lines, checker.HasLen, 1)
|
||||
|
||||
fields = strings.Fields(lines[0])
|
||||
c.Assert(fields, checker.HasLen, 2)
|
||||
c.Assert(fields[0], checker.Equals, "bind-mount-test")
|
||||
c.Assert(fields[1], checker.Equals, bindMountSource)
|
||||
|
||||
// filter by bind mount destination
|
||||
out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountDestination)
|
||||
|
||||
lines = strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
lines = RemoveLinesForExistingElements(lines, existingContainers)
|
||||
c.Assert(lines, checker.HasLen, 1)
|
||||
|
||||
fields = strings.Fields(lines[0])
|
||||
c.Assert(fields, checker.HasLen, 2)
|
||||
c.Assert(fields[0], checker.Equals, "bind-mount-test")
|
||||
c.Assert(fields[1], checker.Equals, bindMountSource)
|
||||
|
||||
// empty results filtering by unknown mount point
|
||||
out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+prefix+slash+"this-path-was-never-mounted")
|
||||
c.Assert(strings.TrimSpace(string(out)), checker.HasLen, 0)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersFilterNetwork(c *check.C) {
|
||||
existing := ExistingContainerIDs(c)
|
||||
|
||||
// TODO default network on Windows is not called "bridge", and creating a
|
||||
// custom network fails on Windows fails with "Error response from daemon: plugin not found")
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// create some containers
|
||||
runSleepingContainer(c, "--net=bridge", "--name=onbridgenetwork")
|
||||
runSleepingContainer(c, "--net=none", "--name=onnonenetwork")
|
||||
|
||||
// Filter docker ps on non existing network
|
||||
out, _ := dockerCmd(c, "ps", "--filter", "network=doesnotexist")
|
||||
containerOut := strings.TrimSpace(string(out))
|
||||
lines := strings.Split(containerOut, "\n")
|
||||
|
||||
// skip header
|
||||
lines = lines[1:]
|
||||
|
||||
// ps output should have no containers
|
||||
c.Assert(RemoveLinesForExistingElements(lines, existing), checker.HasLen, 0)
|
||||
|
||||
// Filter docker ps on network bridge
|
||||
out, _ = dockerCmd(c, "ps", "--filter", "network=bridge")
|
||||
containerOut = strings.TrimSpace(string(out))
|
||||
|
||||
lines = strings.Split(containerOut, "\n")
|
||||
|
||||
// skip header
|
||||
lines = lines[1:]
|
||||
|
||||
// ps output should have only one container
|
||||
c.Assert(RemoveLinesForExistingElements(lines, existing), checker.HasLen, 1)
|
||||
|
||||
// Making sure onbridgenetwork is on the output
|
||||
c.Assert(containerOut, checker.Contains, "onbridgenetwork", check.Commentf("Missing the container on network\n"))
|
||||
|
||||
// Filter docker ps on networks bridge and none
|
||||
out, _ = dockerCmd(c, "ps", "--filter", "network=bridge", "--filter", "network=none")
|
||||
containerOut = strings.TrimSpace(string(out))
|
||||
|
||||
lines = strings.Split(containerOut, "\n")
|
||||
|
||||
// skip header
|
||||
lines = lines[1:]
|
||||
|
||||
//ps output should have both the containers
|
||||
c.Assert(RemoveLinesForExistingElements(lines, existing), checker.HasLen, 2)
|
||||
|
||||
// Making sure onbridgenetwork and onnonenetwork is on the output
|
||||
c.Assert(containerOut, checker.Contains, "onnonenetwork", check.Commentf("Missing the container on none network\n"))
|
||||
c.Assert(containerOut, checker.Contains, "onbridgenetwork", check.Commentf("Missing the container on bridge network\n"))
|
||||
|
||||
nwID, _ := dockerCmd(c, "network", "inspect", "--format", "{{.ID}}", "bridge")
|
||||
|
||||
// Filter by network ID
|
||||
out, _ = dockerCmd(c, "ps", "--filter", "network="+nwID)
|
||||
containerOut = strings.TrimSpace(string(out))
|
||||
|
||||
c.Assert(containerOut, checker.Contains, "onbridgenetwork")
|
||||
|
||||
// Filter by partial network ID
|
||||
partialnwID := string(nwID[0:4])
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--filter", "network="+partialnwID)
|
||||
containerOut = strings.TrimSpace(string(out))
|
||||
|
||||
lines = strings.Split(containerOut, "\n")
|
||||
|
||||
// skip header
|
||||
lines = lines[1:]
|
||||
|
||||
// ps output should have only one container
|
||||
c.Assert(RemoveLinesForExistingElements(lines, existing), checker.HasLen, 1)
|
||||
|
||||
// Making sure onbridgenetwork is on the output
|
||||
c.Assert(containerOut, checker.Contains, "onbridgenetwork", check.Commentf("Missing the container on network\n"))
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsByOrder(c *check.C) {
|
||||
out := runSleepingContainer(c, "--name", "xyz-abc")
|
||||
container1 := strings.TrimSpace(out)
|
||||
|
||||
out = runSleepingContainer(c, "--name", "xyz-123")
|
||||
container2 := strings.TrimSpace(out)
|
||||
|
||||
runSleepingContainer(c, "--name", "789-abc")
|
||||
runSleepingContainer(c, "--name", "789-123")
|
||||
|
||||
// Run multiple time should have the same result
|
||||
out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, fmt.Sprintf("%s\n%s", container2, container1))
|
||||
|
||||
// Run multiple time should have the same result
|
||||
out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined()
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, fmt.Sprintf("%s\n%s", container2, container1))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsListContainersFilterPorts(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
existingContainers := ExistingContainerIDs(c)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "--publish=80", "busybox", "top")
|
||||
id1 := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "run", "-d", "--expose=8080", "busybox", "top")
|
||||
id2 := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--no-trunc", "-q")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, id2)
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-8080/udp")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), id2)
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8081")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), id2)
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-81")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), id2)
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=80/tcp")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), id2)
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8080/tcp")
|
||||
out = RemoveOutputForExistingElements(out, existingContainers)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), id1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, id2)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsNotShowLinknamesOfDeletedContainer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, MinimumAPIVersion("1.31"))
|
||||
existingContainers := ExistingContainerNames(c)
|
||||
|
||||
dockerCmd(c, "create", "--name=aaa", "busybox", "top")
|
||||
dockerCmd(c, "create", "--name=bbb", "--link=aaa", "busybox", "top")
|
||||
|
||||
out, _ := dockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}")
|
||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
lines = RemoveLinesForExistingElements(lines, existingContainers)
|
||||
expected := []string{"bbb", "aaa,bbb/aaa"}
|
||||
var names []string
|
||||
names = append(names, lines...)
|
||||
c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with non-truncated names: %v, got: %v", expected, names))
|
||||
|
||||
dockerCmd(c, "rm", "bbb")
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}")
|
||||
out = RemoveOutputForExistingElements(out, existingContainers)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "aaa")
|
||||
}
|
470
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_pull_local_test.go
generated
vendored
Normal file
470
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_pull_local_test.go
generated
vendored
Normal file
|
@ -0,0 +1,470 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/manifest/manifestlist"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// testPullImageWithAliases pulls a specific image tag and verifies that any aliases (i.e., other
|
||||
// tags for the same image) are not also pulled down.
|
||||
//
|
||||
// Ref: docker/docker#8141
|
||||
func testPullImageWithAliases(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
|
||||
var repos []string
|
||||
for _, tag := range []string{"recent", "fresh"} {
|
||||
repos = append(repos, fmt.Sprintf("%v:%v", repoName, tag))
|
||||
}
|
||||
|
||||
// Tag and push the same image multiple times.
|
||||
for _, repo := range repos {
|
||||
dockerCmd(c, "tag", "busybox", repo)
|
||||
dockerCmd(c, "push", repo)
|
||||
}
|
||||
|
||||
// Clear local images store.
|
||||
args := append([]string{"rmi"}, repos...)
|
||||
dockerCmd(c, args...)
|
||||
|
||||
// Pull a single tag and verify it doesn't bring down all aliases.
|
||||
dockerCmd(c, "pull", repos[0])
|
||||
dockerCmd(c, "inspect", repos[0])
|
||||
for _, repo := range repos[1:] {
|
||||
_, _, err := dockerCmdWithError("inspect", repo)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("Image %v shouldn't have been pulled down", repo))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPullImageWithAliases(c *check.C) {
|
||||
testPullImageWithAliases(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPullImageWithAliases(c *check.C) {
|
||||
testPullImageWithAliases(c)
|
||||
}
|
||||
|
||||
// testConcurrentPullWholeRepo pulls the same repo concurrently.
|
||||
func testConcurrentPullWholeRepo(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
|
||||
var repos []string
|
||||
for _, tag := range []string{"recent", "fresh", "todays"} {
|
||||
repo := fmt.Sprintf("%v:%v", repoName, tag)
|
||||
buildImageSuccessfully(c, repo, build.WithDockerfile(fmt.Sprintf(`
|
||||
FROM busybox
|
||||
ENTRYPOINT ["/bin/echo"]
|
||||
ENV FOO foo
|
||||
ENV BAR bar
|
||||
CMD echo %s
|
||||
`, repo)))
|
||||
dockerCmd(c, "push", repo)
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
|
||||
// Clear local images store.
|
||||
args := append([]string{"rmi"}, repos...)
|
||||
dockerCmd(c, args...)
|
||||
|
||||
// Run multiple re-pulls concurrently
|
||||
results := make(chan error)
|
||||
numPulls := 3
|
||||
|
||||
for i := 0; i != numPulls; i++ {
|
||||
go func() {
|
||||
result := icmd.RunCommand(dockerBinary, "pull", "-a", repoName)
|
||||
results <- result.Error
|
||||
}()
|
||||
}
|
||||
|
||||
// These checks are separate from the loop above because the check
|
||||
// package is not goroutine-safe.
|
||||
for i := 0; i != numPulls; i++ {
|
||||
err := <-results
|
||||
c.Assert(err, checker.IsNil, check.Commentf("concurrent pull failed with error: %v", err))
|
||||
}
|
||||
|
||||
// Ensure all tags were pulled successfully
|
||||
for _, repo := range repos {
|
||||
dockerCmd(c, "inspect", repo)
|
||||
out, _ := dockerCmd(c, "run", "--rm", repo)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "/bin/sh -c echo "+repo)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) testConcurrentPullWholeRepo(c *check.C) {
|
||||
testConcurrentPullWholeRepo(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) testConcurrentPullWholeRepo(c *check.C) {
|
||||
testConcurrentPullWholeRepo(c)
|
||||
}
|
||||
|
||||
// testConcurrentFailingPull tries a concurrent pull that doesn't succeed.
|
||||
func testConcurrentFailingPull(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
|
||||
// Run multiple pulls concurrently
|
||||
results := make(chan error)
|
||||
numPulls := 3
|
||||
|
||||
for i := 0; i != numPulls; i++ {
|
||||
go func() {
|
||||
result := icmd.RunCommand(dockerBinary, "pull", repoName+":asdfasdf")
|
||||
results <- result.Error
|
||||
}()
|
||||
}
|
||||
|
||||
// These checks are separate from the loop above because the check
|
||||
// package is not goroutine-safe.
|
||||
for i := 0; i != numPulls; i++ {
|
||||
err := <-results
|
||||
c.Assert(err, checker.NotNil, check.Commentf("expected pull to fail"))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) testConcurrentFailingPull(c *check.C) {
|
||||
testConcurrentFailingPull(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) testConcurrentFailingPull(c *check.C) {
|
||||
testConcurrentFailingPull(c)
|
||||
}
|
||||
|
||||
// testConcurrentPullMultipleTags pulls multiple tags from the same repo
|
||||
// concurrently.
|
||||
func testConcurrentPullMultipleTags(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
|
||||
var repos []string
|
||||
for _, tag := range []string{"recent", "fresh", "todays"} {
|
||||
repo := fmt.Sprintf("%v:%v", repoName, tag)
|
||||
buildImageSuccessfully(c, repo, build.WithDockerfile(fmt.Sprintf(`
|
||||
FROM busybox
|
||||
ENTRYPOINT ["/bin/echo"]
|
||||
ENV FOO foo
|
||||
ENV BAR bar
|
||||
CMD echo %s
|
||||
`, repo)))
|
||||
dockerCmd(c, "push", repo)
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
|
||||
// Clear local images store.
|
||||
args := append([]string{"rmi"}, repos...)
|
||||
dockerCmd(c, args...)
|
||||
|
||||
// Re-pull individual tags, in parallel
|
||||
results := make(chan error)
|
||||
|
||||
for _, repo := range repos {
|
||||
go func(repo string) {
|
||||
result := icmd.RunCommand(dockerBinary, "pull", repo)
|
||||
results <- result.Error
|
||||
}(repo)
|
||||
}
|
||||
|
||||
// These checks are separate from the loop above because the check
|
||||
// package is not goroutine-safe.
|
||||
for range repos {
|
||||
err := <-results
|
||||
c.Assert(err, checker.IsNil, check.Commentf("concurrent pull failed with error: %v", err))
|
||||
}
|
||||
|
||||
// Ensure all tags were pulled successfully
|
||||
for _, repo := range repos {
|
||||
dockerCmd(c, "inspect", repo)
|
||||
out, _ := dockerCmd(c, "run", "--rm", repo)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "/bin/sh -c echo "+repo)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestConcurrentPullMultipleTags(c *check.C) {
|
||||
testConcurrentPullMultipleTags(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestConcurrentPullMultipleTags(c *check.C) {
|
||||
testConcurrentPullMultipleTags(c)
|
||||
}
|
||||
|
||||
// testPullIDStability verifies that pushing an image and pulling it back
|
||||
// preserves the image ID.
|
||||
func testPullIDStability(c *check.C) {
|
||||
derivedImage := privateRegistryURL + "/dockercli/id-stability"
|
||||
baseImage := "busybox"
|
||||
|
||||
buildImageSuccessfully(c, derivedImage, build.WithDockerfile(fmt.Sprintf(`
|
||||
FROM %s
|
||||
ENV derived true
|
||||
ENV asdf true
|
||||
RUN dd if=/dev/zero of=/file bs=1024 count=1024
|
||||
CMD echo %s
|
||||
`, baseImage, derivedImage)))
|
||||
|
||||
originalID := getIDByName(c, derivedImage)
|
||||
dockerCmd(c, "push", derivedImage)
|
||||
|
||||
// Pull
|
||||
out, _ := dockerCmd(c, "pull", derivedImage)
|
||||
if strings.Contains(out, "Pull complete") {
|
||||
c.Fatalf("repull redownloaded a layer: %s", out)
|
||||
}
|
||||
|
||||
derivedIDAfterPull := getIDByName(c, derivedImage)
|
||||
|
||||
if derivedIDAfterPull != originalID {
|
||||
c.Fatal("image's ID unexpectedly changed after a repush/repull")
|
||||
}
|
||||
|
||||
// Make sure the image runs correctly
|
||||
out, _ = dockerCmd(c, "run", "--rm", derivedImage)
|
||||
if strings.TrimSpace(out) != derivedImage {
|
||||
c.Fatalf("expected %s; got %s", derivedImage, out)
|
||||
}
|
||||
|
||||
// Confirm that repushing and repulling does not change the computed ID
|
||||
dockerCmd(c, "push", derivedImage)
|
||||
dockerCmd(c, "rmi", derivedImage)
|
||||
dockerCmd(c, "pull", derivedImage)
|
||||
|
||||
derivedIDAfterPull = getIDByName(c, derivedImage)
|
||||
|
||||
if derivedIDAfterPull != originalID {
|
||||
c.Fatal("image's ID unexpectedly changed after a repush/repull")
|
||||
}
|
||||
|
||||
// Make sure the image still runs
|
||||
out, _ = dockerCmd(c, "run", "--rm", derivedImage)
|
||||
if strings.TrimSpace(out) != derivedImage {
|
||||
c.Fatalf("expected %s; got %s", derivedImage, out)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPullIDStability(c *check.C) {
|
||||
testPullIDStability(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPullIDStability(c *check.C) {
|
||||
testPullIDStability(c)
|
||||
}
|
||||
|
||||
// #21213
|
||||
func testPullNoLayers(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/scratch", privateRegistryURL)
|
||||
|
||||
buildImageSuccessfully(c, repoName, build.WithDockerfile(`
|
||||
FROM scratch
|
||||
ENV foo bar`))
|
||||
dockerCmd(c, "push", repoName)
|
||||
dockerCmd(c, "rmi", repoName)
|
||||
dockerCmd(c, "pull", repoName)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPullNoLayers(c *check.C) {
|
||||
testPullNoLayers(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPullNoLayers(c *check.C) {
|
||||
testPullNoLayers(c)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPullManifestList(c *check.C) {
|
||||
testRequires(c, NotArm)
|
||||
pushDigest, err := setupImage(c)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
||||
|
||||
// Inject a manifest list into the registry
|
||||
manifestList := &manifestlist.ManifestList{
|
||||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 2,
|
||||
MediaType: manifestlist.MediaTypeManifestList,
|
||||
},
|
||||
Manifests: []manifestlist.ManifestDescriptor{
|
||||
{
|
||||
Descriptor: distribution.Descriptor{
|
||||
Digest: "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b",
|
||||
Size: 3253,
|
||||
MediaType: schema2.MediaTypeManifest,
|
||||
},
|
||||
Platform: manifestlist.PlatformSpec{
|
||||
Architecture: "bogus_arch",
|
||||
OS: "bogus_os",
|
||||
},
|
||||
},
|
||||
{
|
||||
Descriptor: distribution.Descriptor{
|
||||
Digest: pushDigest,
|
||||
Size: 3253,
|
||||
MediaType: schema2.MediaTypeManifest,
|
||||
},
|
||||
Platform: manifestlist.PlatformSpec{
|
||||
Architecture: runtime.GOARCH,
|
||||
OS: runtime.GOOS,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
manifestListJSON, err := json.MarshalIndent(manifestList, "", " ")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error marshalling manifest list"))
|
||||
|
||||
manifestListDigest := digest.FromBytes(manifestListJSON)
|
||||
hexDigest := manifestListDigest.Hex()
|
||||
|
||||
registryV2Path := s.reg.Path()
|
||||
|
||||
// Write manifest list to blob store
|
||||
blobDir := filepath.Join(registryV2Path, "blobs", "sha256", hexDigest[:2], hexDigest)
|
||||
err = os.MkdirAll(blobDir, 0755)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error creating blob dir"))
|
||||
blobPath := filepath.Join(blobDir, "data")
|
||||
err = ioutil.WriteFile(blobPath, []byte(manifestListJSON), 0644)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error writing manifest list"))
|
||||
|
||||
// Add to revision store
|
||||
revisionDir := filepath.Join(registryV2Path, "repositories", remoteRepoName, "_manifests", "revisions", "sha256", hexDigest)
|
||||
err = os.Mkdir(revisionDir, 0755)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error creating revision dir"))
|
||||
revisionPath := filepath.Join(revisionDir, "link")
|
||||
err = ioutil.WriteFile(revisionPath, []byte(manifestListDigest.String()), 0644)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error writing revision link"))
|
||||
|
||||
// Update tag
|
||||
tagPath := filepath.Join(registryV2Path, "repositories", remoteRepoName, "_manifests", "tags", "latest", "current", "link")
|
||||
err = ioutil.WriteFile(tagPath, []byte(manifestListDigest.String()), 0644)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("error writing tag link"))
|
||||
|
||||
// Verify that the image can be pulled through the manifest list.
|
||||
out, _ := dockerCmd(c, "pull", repoName)
|
||||
|
||||
// The pull output includes "Digest: <digest>", so find that
|
||||
matches := digestRegex.FindStringSubmatch(out)
|
||||
c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from pull output: %s", out))
|
||||
pullDigest := matches[1]
|
||||
|
||||
// Make sure the pushed and pull digests match
|
||||
c.Assert(manifestListDigest.String(), checker.Equals, pullDigest)
|
||||
|
||||
// Was the image actually created?
|
||||
dockerCmd(c, "inspect", repoName)
|
||||
|
||||
dockerCmd(c, "rmi", repoName)
|
||||
}
|
||||
|
||||
// #23100
|
||||
func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuthLoginWithScheme(c *check.C) {
|
||||
osPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", osPath)
|
||||
|
||||
workingDir, err := os.Getwd()
|
||||
c.Assert(err, checker.IsNil)
|
||||
absolute, err := filepath.Abs(filepath.Join(workingDir, "fixtures", "auth"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
testPath := fmt.Sprintf("%s%c%s", osPath, filepath.ListSeparator, absolute)
|
||||
|
||||
os.Setenv("PATH", testPath)
|
||||
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox:authtest", privateRegistryURL)
|
||||
|
||||
tmp, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
externalAuthConfig := `{ "credsStore": "shell-test" }`
|
||||
|
||||
configPath := filepath.Join(tmp, "config.json")
|
||||
err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
|
||||
|
||||
b, err := ioutil.ReadFile(configPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(b), checker.Not(checker.Contains), "\"auth\":")
|
||||
|
||||
dockerCmd(c, "--config", tmp, "tag", "busybox", repoName)
|
||||
dockerCmd(c, "--config", tmp, "push", repoName)
|
||||
|
||||
dockerCmd(c, "--config", tmp, "logout", privateRegistryURL)
|
||||
dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), "https://"+privateRegistryURL)
|
||||
dockerCmd(c, "--config", tmp, "pull", repoName)
|
||||
|
||||
// likewise push should work
|
||||
repoName2 := fmt.Sprintf("%v/dockercli/busybox:nocreds", privateRegistryURL)
|
||||
dockerCmd(c, "tag", repoName, repoName2)
|
||||
dockerCmd(c, "--config", tmp, "push", repoName2)
|
||||
|
||||
// logout should work w scheme also because it will be stripped
|
||||
dockerCmd(c, "--config", tmp, "logout", "https://"+privateRegistryURL)
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuth(c *check.C) {
|
||||
osPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", osPath)
|
||||
|
||||
workingDir, err := os.Getwd()
|
||||
c.Assert(err, checker.IsNil)
|
||||
absolute, err := filepath.Abs(filepath.Join(workingDir, "fixtures", "auth"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
testPath := fmt.Sprintf("%s%c%s", osPath, filepath.ListSeparator, absolute)
|
||||
|
||||
os.Setenv("PATH", testPath)
|
||||
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox:authtest", privateRegistryURL)
|
||||
|
||||
tmp, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
externalAuthConfig := `{ "credsStore": "shell-test" }`
|
||||
|
||||
configPath := filepath.Join(tmp, "config.json")
|
||||
err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
|
||||
|
||||
b, err := ioutil.ReadFile(configPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(b), checker.Not(checker.Contains), "\"auth\":")
|
||||
|
||||
dockerCmd(c, "--config", tmp, "tag", "busybox", repoName)
|
||||
dockerCmd(c, "--config", tmp, "push", repoName)
|
||||
|
||||
dockerCmd(c, "--config", tmp, "pull", repoName)
|
||||
}
|
||||
|
||||
// TestRunImplicitPullWithNoTag should pull implicitly only the default tag (latest)
|
||||
func (s *DockerRegistrySuite) TestRunImplicitPullWithNoTag(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
repo := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
repoTag1 := fmt.Sprintf("%v:latest", repo)
|
||||
repoTag2 := fmt.Sprintf("%v:t1", repo)
|
||||
// tag the image and upload it to the private registry
|
||||
dockerCmd(c, "tag", "busybox", repoTag1)
|
||||
dockerCmd(c, "tag", "busybox", repoTag2)
|
||||
dockerCmd(c, "push", repo)
|
||||
dockerCmd(c, "rmi", repoTag1)
|
||||
dockerCmd(c, "rmi", repoTag2)
|
||||
|
||||
out, _ := dockerCmd(c, "run", repo)
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("Unable to find image '%s:latest' locally", repo))
|
||||
|
||||
// There should be only one line for repo, the one with repo:latest
|
||||
outImageCmd, _ := dockerCmd(c, "images", repo)
|
||||
splitOutImageCmd := strings.Split(strings.TrimSpace(outImageCmd), "\n")
|
||||
c.Assert(splitOutImageCmd, checker.HasLen, 2)
|
||||
}
|
274
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_pull_test.go
generated
vendored
Normal file
274
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_pull_test.go
generated
vendored
Normal file
|
@ -0,0 +1,274 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
// TestPullFromCentralRegistry pulls an image from the central registry and verifies that the client
|
||||
// prints all expected output.
|
||||
func (s *DockerHubPullSuite) TestPullFromCentralRegistry(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out := s.Cmd(c, "pull", "hello-world")
|
||||
defer deleteImages("hello-world")
|
||||
|
||||
c.Assert(out, checker.Contains, "Using default tag: latest", check.Commentf("expected the 'latest' tag to be automatically assumed"))
|
||||
c.Assert(out, checker.Contains, "Pulling from library/hello-world", check.Commentf("expected the 'library/' prefix to be automatically assumed"))
|
||||
c.Assert(out, checker.Contains, "Downloaded newer image for hello-world:latest")
|
||||
|
||||
matches := regexp.MustCompile(`Digest: (.+)\n`).FindAllStringSubmatch(out, -1)
|
||||
c.Assert(len(matches), checker.Equals, 1, check.Commentf("expected exactly one image digest in the output"))
|
||||
c.Assert(len(matches[0]), checker.Equals, 2, check.Commentf("unexpected number of submatches for the digest"))
|
||||
_, err := digest.Parse(matches[0][1])
|
||||
c.Check(err, checker.IsNil, check.Commentf("invalid digest %q in output", matches[0][1]))
|
||||
|
||||
// We should have a single entry in images.
|
||||
img := strings.TrimSpace(s.Cmd(c, "images"))
|
||||
splitImg := strings.Split(img, "\n")
|
||||
c.Assert(splitImg, checker.HasLen, 2)
|
||||
c.Assert(splitImg[1], checker.Matches, `hello-world\s+latest.*?`, check.Commentf("invalid output for `docker images` (expected image and tag name"))
|
||||
}
|
||||
|
||||
// TestPullNonExistingImage pulls non-existing images from the central registry, with different
|
||||
// combinations of implicit tag and library prefix.
|
||||
func (s *DockerHubPullSuite) TestPullNonExistingImage(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
type entry struct {
|
||||
repo string
|
||||
alias string
|
||||
tag string
|
||||
}
|
||||
|
||||
entries := []entry{
|
||||
{"asdfasdf", "asdfasdf", "foobar"},
|
||||
{"asdfasdf", "library/asdfasdf", "foobar"},
|
||||
{"asdfasdf", "asdfasdf", ""},
|
||||
{"asdfasdf", "asdfasdf", "latest"},
|
||||
{"asdfasdf", "library/asdfasdf", ""},
|
||||
{"asdfasdf", "library/asdfasdf", "latest"},
|
||||
}
|
||||
|
||||
// The option field indicates "-a" or not.
|
||||
type record struct {
|
||||
e entry
|
||||
option string
|
||||
out string
|
||||
err error
|
||||
}
|
||||
|
||||
// Execute 'docker pull' in parallel, pass results (out, err) and
|
||||
// necessary information ("-a" or not, and the image name) to channel.
|
||||
var group sync.WaitGroup
|
||||
recordChan := make(chan record, len(entries)*2)
|
||||
for _, e := range entries {
|
||||
group.Add(1)
|
||||
go func(e entry) {
|
||||
defer group.Done()
|
||||
repoName := e.alias
|
||||
if e.tag != "" {
|
||||
repoName += ":" + e.tag
|
||||
}
|
||||
out, err := s.CmdWithError("pull", repoName)
|
||||
recordChan <- record{e, "", out, err}
|
||||
}(e)
|
||||
if e.tag == "" {
|
||||
// pull -a on a nonexistent registry should fall back as well
|
||||
group.Add(1)
|
||||
go func(e entry) {
|
||||
defer group.Done()
|
||||
out, err := s.CmdWithError("pull", "-a", e.alias)
|
||||
recordChan <- record{e, "-a", out, err}
|
||||
}(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for completion
|
||||
group.Wait()
|
||||
close(recordChan)
|
||||
|
||||
// Process the results (out, err).
|
||||
for record := range recordChan {
|
||||
if len(record.option) == 0 {
|
||||
c.Assert(record.err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", record.out))
|
||||
c.Assert(record.out, checker.Contains, fmt.Sprintf("pull access denied for %s, repository does not exist or may require 'docker login'", record.e.repo), check.Commentf("expected image not found error messages"))
|
||||
} else {
|
||||
// pull -a on a nonexistent registry should fall back as well
|
||||
c.Assert(record.err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", record.out))
|
||||
c.Assert(record.out, checker.Contains, fmt.Sprintf("pull access denied for %s, repository does not exist or may require 'docker login'", record.e.repo), check.Commentf("expected image not found error messages"))
|
||||
c.Assert(record.out, checker.Not(checker.Contains), "unauthorized", check.Commentf(`message should not contain "unauthorized"`))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TestPullFromCentralRegistryImplicitRefParts pulls an image from the central registry and verifies
|
||||
// that pulling the same image with different combinations of implicit elements of the image
|
||||
// reference (tag, repository, central registry url, ...) doesn't trigger a new pull nor leads to
|
||||
// multiple images.
|
||||
func (s *DockerHubPullSuite) TestPullFromCentralRegistryImplicitRefParts(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// Pull hello-world from v2
|
||||
pullFromV2 := func(ref string) (int, string) {
|
||||
out := s.Cmd(c, "pull", "hello-world")
|
||||
v1Retries := 0
|
||||
for strings.Contains(out, "this image was pulled from a legacy registry") {
|
||||
// Some network errors may cause fallbacks to the v1
|
||||
// protocol, which would violate the test's assumption
|
||||
// that it will get the same images. To make the test
|
||||
// more robust against these network glitches, allow a
|
||||
// few retries if we end up with a v1 pull.
|
||||
|
||||
if v1Retries > 2 {
|
||||
c.Fatalf("too many v1 fallback incidents when pulling %s", ref)
|
||||
}
|
||||
|
||||
s.Cmd(c, "rmi", ref)
|
||||
out = s.Cmd(c, "pull", ref)
|
||||
|
||||
v1Retries++
|
||||
}
|
||||
|
||||
return v1Retries, out
|
||||
}
|
||||
|
||||
pullFromV2("hello-world")
|
||||
defer deleteImages("hello-world")
|
||||
|
||||
s.Cmd(c, "tag", "hello-world", "hello-world-backup")
|
||||
|
||||
for _, ref := range []string{
|
||||
"hello-world",
|
||||
"hello-world:latest",
|
||||
"library/hello-world",
|
||||
"library/hello-world:latest",
|
||||
"docker.io/library/hello-world",
|
||||
"index.docker.io/library/hello-world",
|
||||
} {
|
||||
var out string
|
||||
for {
|
||||
var v1Retries int
|
||||
v1Retries, out = pullFromV2(ref)
|
||||
|
||||
// Keep repeating the test case until we don't hit a v1
|
||||
// fallback case. We won't get the right "Image is up
|
||||
// to date" message if the local image was replaced
|
||||
// with one pulled from v1.
|
||||
if v1Retries == 0 {
|
||||
break
|
||||
}
|
||||
s.Cmd(c, "rmi", ref)
|
||||
s.Cmd(c, "tag", "hello-world-backup", "hello-world")
|
||||
}
|
||||
c.Assert(out, checker.Contains, "Image is up to date for hello-world:latest")
|
||||
}
|
||||
|
||||
s.Cmd(c, "rmi", "hello-world-backup")
|
||||
|
||||
// We should have a single entry in images.
|
||||
img := strings.TrimSpace(s.Cmd(c, "images"))
|
||||
splitImg := strings.Split(img, "\n")
|
||||
c.Assert(splitImg, checker.HasLen, 2)
|
||||
c.Assert(splitImg[1], checker.Matches, `hello-world\s+latest.*?`, check.Commentf("invalid output for `docker images` (expected image and tag name"))
|
||||
}
|
||||
|
||||
// TestPullScratchNotAllowed verifies that pulling 'scratch' is rejected.
|
||||
func (s *DockerHubPullSuite) TestPullScratchNotAllowed(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, err := s.CmdWithError("pull", "scratch")
|
||||
c.Assert(err, checker.NotNil, check.Commentf("expected pull of scratch to fail"))
|
||||
c.Assert(out, checker.Contains, "'scratch' is a reserved name")
|
||||
c.Assert(out, checker.Not(checker.Contains), "Pulling repository scratch")
|
||||
}
|
||||
|
||||
// TestPullAllTagsFromCentralRegistry pulls using `all-tags` for a given image and verifies that it
|
||||
// results in more images than a naked pull.
|
||||
func (s *DockerHubPullSuite) TestPullAllTagsFromCentralRegistry(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
s.Cmd(c, "pull", "dockercore/engine-pull-all-test-fixture")
|
||||
outImageCmd := s.Cmd(c, "images", "dockercore/engine-pull-all-test-fixture")
|
||||
splitOutImageCmd := strings.Split(strings.TrimSpace(outImageCmd), "\n")
|
||||
c.Assert(splitOutImageCmd, checker.HasLen, 2)
|
||||
|
||||
s.Cmd(c, "pull", "--all-tags=true", "dockercore/engine-pull-all-test-fixture")
|
||||
outImageAllTagCmd := s.Cmd(c, "images", "dockercore/engine-pull-all-test-fixture")
|
||||
linesCount := strings.Count(outImageAllTagCmd, "\n")
|
||||
c.Assert(linesCount, checker.GreaterThan, 2, check.Commentf("pulling all tags should provide more than two images, got %s", outImageAllTagCmd))
|
||||
|
||||
// Verify that the line for 'dockercore/engine-pull-all-test-fixture:latest' is left unchanged.
|
||||
var latestLine string
|
||||
for _, line := range strings.Split(outImageAllTagCmd, "\n") {
|
||||
if strings.HasPrefix(line, "dockercore/engine-pull-all-test-fixture") && strings.Contains(line, "latest") {
|
||||
latestLine = line
|
||||
break
|
||||
}
|
||||
}
|
||||
c.Assert(latestLine, checker.Not(checker.Equals), "", check.Commentf("no entry for dockercore/engine-pull-all-test-fixture:latest found after pulling all tags"))
|
||||
|
||||
splitLatest := strings.Fields(latestLine)
|
||||
splitCurrent := strings.Fields(splitOutImageCmd[1])
|
||||
|
||||
// Clear relative creation times, since these can easily change between
|
||||
// two invocations of "docker images". Without this, the test can fail
|
||||
// like this:
|
||||
// ... obtained []string = []string{"busybox", "latest", "d9551b4026f0", "27", "minutes", "ago", "1.113", "MB"}
|
||||
// ... expected []string = []string{"busybox", "latest", "d9551b4026f0", "26", "minutes", "ago", "1.113", "MB"}
|
||||
splitLatest[3] = ""
|
||||
splitLatest[4] = ""
|
||||
splitLatest[5] = ""
|
||||
splitCurrent[3] = ""
|
||||
splitCurrent[4] = ""
|
||||
splitCurrent[5] = ""
|
||||
|
||||
c.Assert(splitLatest, checker.DeepEquals, splitCurrent, check.Commentf("dockercore/engine-pull-all-test-fixture:latest was changed after pulling all tags"))
|
||||
}
|
||||
|
||||
// TestPullClientDisconnect kills the client during a pull operation and verifies that the operation
|
||||
// gets cancelled.
|
||||
//
|
||||
// Ref: docker/docker#15589
|
||||
func (s *DockerHubPullSuite) TestPullClientDisconnect(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
repoName := "hello-world:latest"
|
||||
|
||||
pullCmd := s.MakeCmd("pull", repoName)
|
||||
stdout, err := pullCmd.StdoutPipe()
|
||||
c.Assert(err, checker.IsNil)
|
||||
err = pullCmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
go pullCmd.Wait()
|
||||
|
||||
// Cancel as soon as we get some output.
|
||||
buf := make([]byte, 10)
|
||||
_, err = stdout.Read(buf)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = pullCmd.Process.Kill()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
_, err = s.CmdWithError("inspect", repoName)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("image was pulled after client disconnected"))
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/docker/docker/issues/26429
|
||||
func (s *DockerSuite) TestPullLinuxImageFailsOnWindows(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows, Network)
|
||||
_, _, err := dockerCmdWithError("pull", "ubuntu")
|
||||
c.Assert(err.Error(), checker.Contains, "no matching manifest")
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/docker/docker/issues/28892
|
||||
func (s *DockerSuite) TestPullWindowsImageFailsOnLinux(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, Network)
|
||||
_, _, err := dockerCmdWithError("pull", "microsoft/nanoserver")
|
||||
c.Assert(err.Error(), checker.Contains, "cannot be used on this platform")
|
||||
}
|
382
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_push_test.go
generated
vendored
Normal file
382
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_push_test.go
generated
vendored
Normal file
|
@ -0,0 +1,382 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// Pushing an image to a private registry.
|
||||
func testPushBusyboxImage(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
// tag the image to upload it to the private registry
|
||||
dockerCmd(c, "tag", "busybox", repoName)
|
||||
// push the image to the registry
|
||||
dockerCmd(c, "push", repoName)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPushBusyboxImage(c *check.C) {
|
||||
testPushBusyboxImage(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPushBusyboxImage(c *check.C) {
|
||||
testPushBusyboxImage(c)
|
||||
}
|
||||
|
||||
// pushing an image without a prefix should throw an error
|
||||
func (s *DockerSuite) TestPushUnprefixedRepo(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("push", "busybox")
|
||||
c.Assert(err, check.NotNil, check.Commentf("pushing an unprefixed repo didn't result in a non-zero exit status: %s", out))
|
||||
}
|
||||
|
||||
func testPushUntagged(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
expected := "An image does not exist locally with the tag"
|
||||
|
||||
out, _, err := dockerCmdWithError("push", repoName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("pushing the image to the private registry should have failed: output %q", out))
|
||||
c.Assert(out, checker.Contains, expected, check.Commentf("pushing the image failed"))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPushUntagged(c *check.C) {
|
||||
testPushUntagged(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPushUntagged(c *check.C) {
|
||||
testPushUntagged(c)
|
||||
}
|
||||
|
||||
func testPushBadTag(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox:latest", privateRegistryURL)
|
||||
expected := "does not exist"
|
||||
|
||||
out, _, err := dockerCmdWithError("push", repoName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("pushing the image to the private registry should have failed: output %q", out))
|
||||
c.Assert(out, checker.Contains, expected, check.Commentf("pushing the image failed"))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPushBadTag(c *check.C) {
|
||||
testPushBadTag(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPushBadTag(c *check.C) {
|
||||
testPushBadTag(c)
|
||||
}
|
||||
|
||||
func testPushMultipleTags(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
repoTag1 := fmt.Sprintf("%v/dockercli/busybox:t1", privateRegistryURL)
|
||||
repoTag2 := fmt.Sprintf("%v/dockercli/busybox:t2", privateRegistryURL)
|
||||
// tag the image and upload it to the private registry
|
||||
dockerCmd(c, "tag", "busybox", repoTag1)
|
||||
|
||||
dockerCmd(c, "tag", "busybox", repoTag2)
|
||||
|
||||
dockerCmd(c, "push", repoName)
|
||||
|
||||
// Ensure layer list is equivalent for repoTag1 and repoTag2
|
||||
out1, _ := dockerCmd(c, "pull", repoTag1)
|
||||
|
||||
imageAlreadyExists := ": Image already exists"
|
||||
var out1Lines []string
|
||||
for _, outputLine := range strings.Split(out1, "\n") {
|
||||
if strings.Contains(outputLine, imageAlreadyExists) {
|
||||
out1Lines = append(out1Lines, outputLine)
|
||||
}
|
||||
}
|
||||
|
||||
out2, _ := dockerCmd(c, "pull", repoTag2)
|
||||
|
||||
var out2Lines []string
|
||||
for _, outputLine := range strings.Split(out2, "\n") {
|
||||
if strings.Contains(outputLine, imageAlreadyExists) {
|
||||
out1Lines = append(out1Lines, outputLine)
|
||||
}
|
||||
}
|
||||
c.Assert(out2Lines, checker.HasLen, len(out1Lines))
|
||||
|
||||
for i := range out1Lines {
|
||||
c.Assert(out1Lines[i], checker.Equals, out2Lines[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPushMultipleTags(c *check.C) {
|
||||
testPushMultipleTags(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPushMultipleTags(c *check.C) {
|
||||
testPushMultipleTags(c)
|
||||
}
|
||||
|
||||
func testPushEmptyLayer(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/emptylayer", privateRegistryURL)
|
||||
emptyTarball, err := ioutil.TempFile("", "empty_tarball")
|
||||
c.Assert(err, check.IsNil, check.Commentf("Unable to create test file"))
|
||||
|
||||
tw := tar.NewWriter(emptyTarball)
|
||||
err = tw.Close()
|
||||
c.Assert(err, check.IsNil, check.Commentf("Error creating empty tarball"))
|
||||
|
||||
freader, err := os.Open(emptyTarball.Name())
|
||||
c.Assert(err, check.IsNil, check.Commentf("Could not open test tarball"))
|
||||
defer freader.Close()
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "import", "-", repoName},
|
||||
Stdin: freader,
|
||||
}).Assert(c, icmd.Success)
|
||||
|
||||
// Now verify we can push it
|
||||
out, _, err := dockerCmdWithError("push", repoName)
|
||||
c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out))
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestPushEmptyLayer(c *check.C) {
|
||||
testPushEmptyLayer(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestPushEmptyLayer(c *check.C) {
|
||||
testPushEmptyLayer(c)
|
||||
}
|
||||
|
||||
// testConcurrentPush pushes multiple tags to the same repo
|
||||
// concurrently.
|
||||
func testConcurrentPush(c *check.C) {
|
||||
repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
|
||||
var repos []string
|
||||
for _, tag := range []string{"push1", "push2", "push3"} {
|
||||
repo := fmt.Sprintf("%v:%v", repoName, tag)
|
||||
buildImageSuccessfully(c, repo, build.WithDockerfile(fmt.Sprintf(`
|
||||
FROM busybox
|
||||
ENTRYPOINT ["/bin/echo"]
|
||||
ENV FOO foo
|
||||
ENV BAR bar
|
||||
CMD echo %s
|
||||
`, repo)))
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
|
||||
// Push tags, in parallel
|
||||
results := make(chan error)
|
||||
|
||||
for _, repo := range repos {
|
||||
go func(repo string) {
|
||||
result := icmd.RunCommand(dockerBinary, "push", repo)
|
||||
results <- result.Error
|
||||
}(repo)
|
||||
}
|
||||
|
||||
for range repos {
|
||||
err := <-results
|
||||
c.Assert(err, checker.IsNil, check.Commentf("concurrent push failed with error: %v", err))
|
||||
}
|
||||
|
||||
// Clear local images store.
|
||||
args := append([]string{"rmi"}, repos...)
|
||||
dockerCmd(c, args...)
|
||||
|
||||
// Re-pull and run individual tags, to make sure pushes succeeded
|
||||
for _, repo := range repos {
|
||||
dockerCmd(c, "pull", repo)
|
||||
dockerCmd(c, "inspect", repo)
|
||||
out, _ := dockerCmd(c, "run", "--rm", repo)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "/bin/sh -c echo "+repo)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestConcurrentPush(c *check.C) {
|
||||
testConcurrentPush(c)
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestConcurrentPush(c *check.C) {
|
||||
testConcurrentPush(c)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TestCrossRepositoryLayerPush(c *check.C) {
|
||||
sourceRepoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
// tag the image to upload it to the private registry
|
||||
dockerCmd(c, "tag", "busybox", sourceRepoName)
|
||||
// push the image to the registry
|
||||
out1, _, err := dockerCmdWithError("push", sourceRepoName)
|
||||
c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out1))
|
||||
// ensure that none of the layers were mounted from another repository during push
|
||||
c.Assert(strings.Contains(out1, "Mounted from"), check.Equals, false)
|
||||
|
||||
digest1 := reference.DigestRegexp.FindString(out1)
|
||||
c.Assert(len(digest1), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
|
||||
|
||||
destRepoName := fmt.Sprintf("%v/dockercli/crossrepopush", privateRegistryURL)
|
||||
// retag the image to upload the same layers to another repo in the same registry
|
||||
dockerCmd(c, "tag", "busybox", destRepoName)
|
||||
// push the image to the registry
|
||||
out2, _, err := dockerCmdWithError("push", destRepoName)
|
||||
c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out2))
|
||||
// ensure that layers were mounted from the first repo during push
|
||||
c.Assert(strings.Contains(out2, "Mounted from dockercli/busybox"), check.Equals, true)
|
||||
|
||||
digest2 := reference.DigestRegexp.FindString(out2)
|
||||
c.Assert(len(digest2), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
|
||||
c.Assert(digest1, check.Equals, digest2)
|
||||
|
||||
// ensure that pushing again produces the same digest
|
||||
out3, _, err := dockerCmdWithError("push", destRepoName)
|
||||
c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out2))
|
||||
|
||||
digest3 := reference.DigestRegexp.FindString(out3)
|
||||
c.Assert(len(digest2), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
|
||||
c.Assert(digest3, check.Equals, digest2)
|
||||
|
||||
// ensure that we can pull and run the cross-repo-pushed repository
|
||||
dockerCmd(c, "rmi", destRepoName)
|
||||
dockerCmd(c, "pull", destRepoName)
|
||||
out4, _ := dockerCmd(c, "run", destRepoName, "echo", "-n", "hello world")
|
||||
c.Assert(out4, check.Equals, "hello world")
|
||||
}
|
||||
|
||||
func (s *DockerSchema1RegistrySuite) TestCrossRepositoryLayerPushNotSupported(c *check.C) {
|
||||
sourceRepoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
|
||||
// tag the image to upload it to the private registry
|
||||
dockerCmd(c, "tag", "busybox", sourceRepoName)
|
||||
// push the image to the registry
|
||||
out1, _, err := dockerCmdWithError("push", sourceRepoName)
|
||||
c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out1))
|
||||
// ensure that none of the layers were mounted from another repository during push
|
||||
c.Assert(strings.Contains(out1, "Mounted from"), check.Equals, false)
|
||||
|
||||
digest1 := reference.DigestRegexp.FindString(out1)
|
||||
c.Assert(len(digest1), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
|
||||
|
||||
destRepoName := fmt.Sprintf("%v/dockercli/crossrepopush", privateRegistryURL)
|
||||
// retag the image to upload the same layers to another repo in the same registry
|
||||
dockerCmd(c, "tag", "busybox", destRepoName)
|
||||
// push the image to the registry
|
||||
out2, _, err := dockerCmdWithError("push", destRepoName)
|
||||
c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out2))
|
||||
// schema1 registry should not support cross-repo layer mounts, so ensure that this does not happen
|
||||
c.Assert(strings.Contains(out2, "Mounted from"), check.Equals, false)
|
||||
|
||||
digest2 := reference.DigestRegexp.FindString(out2)
|
||||
c.Assert(len(digest2), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
|
||||
c.Assert(digest1, check.Not(check.Equals), digest2)
|
||||
|
||||
// ensure that we can pull and run the second pushed repository
|
||||
dockerCmd(c, "rmi", destRepoName)
|
||||
dockerCmd(c, "pull", destRepoName)
|
||||
out3, _ := dockerCmd(c, "run", destRepoName, "echo", "-n", "hello world")
|
||||
c.Assert(out3, check.Equals, "hello world")
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthHtpasswdSuite) TestPushNoCredentialsNoRetry(c *check.C) {
|
||||
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||
dockerCmd(c, "tag", "busybox", repoName)
|
||||
out, _, err := dockerCmdWithError("push", repoName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, check.Not(checker.Contains), "Retrying")
|
||||
c.Assert(out, checker.Contains, "no basic auth credentials")
|
||||
}
|
||||
|
||||
// This may be flaky but it's needed not to regress on unauthorized push, see #21054
|
||||
func (s *DockerSuite) TestPushToCentralRegistryUnauthorized(c *check.C) {
|
||||
testRequires(c, Network)
|
||||
repoName := "test/busybox"
|
||||
dockerCmd(c, "tag", "busybox", repoName)
|
||||
out, _, err := dockerCmdWithError("push", repoName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, check.Not(checker.Contains), "Retrying")
|
||||
}
|
||||
|
||||
func getTestTokenService(status int, body string, retries int) *httptest.Server {
|
||||
var mu sync.Mutex
|
||||
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
mu.Lock()
|
||||
if retries > 0 {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte(`{"errors":[{"code":"UNAVAILABLE","message":"cannot create token at this time"}]}`))
|
||||
retries--
|
||||
} else {
|
||||
w.WriteHeader(status)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte(body))
|
||||
}
|
||||
mu.Unlock()
|
||||
}))
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthTokenSuite) TestPushTokenServiceUnauthResponse(c *check.C) {
|
||||
ts := getTestTokenService(http.StatusUnauthorized, `{"errors": [{"Code":"UNAUTHORIZED", "message": "a message", "detail": null}]}`, 0)
|
||||
defer ts.Close()
|
||||
s.setupRegistryWithTokenService(c, ts.URL)
|
||||
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||
dockerCmd(c, "tag", "busybox", repoName)
|
||||
out, _, err := dockerCmdWithError("push", repoName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Not(checker.Contains), "Retrying")
|
||||
c.Assert(out, checker.Contains, "unauthorized: a message")
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnauthorized(c *check.C) {
|
||||
ts := getTestTokenService(http.StatusUnauthorized, `{"error": "unauthorized"}`, 0)
|
||||
defer ts.Close()
|
||||
s.setupRegistryWithTokenService(c, ts.URL)
|
||||
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||
dockerCmd(c, "tag", "busybox", repoName)
|
||||
out, _, err := dockerCmdWithError("push", repoName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Not(checker.Contains), "Retrying")
|
||||
split := strings.Split(out, "\n")
|
||||
c.Assert(split[len(split)-2], check.Equals, "unauthorized: authentication required")
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseError(c *check.C) {
|
||||
ts := getTestTokenService(http.StatusTooManyRequests, `{"errors": [{"code":"TOOMANYREQUESTS","message":"out of tokens"}]}`, 3)
|
||||
defer ts.Close()
|
||||
s.setupRegistryWithTokenService(c, ts.URL)
|
||||
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||
dockerCmd(c, "tag", "busybox", repoName)
|
||||
out, _, err := dockerCmdWithError("push", repoName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
// TODO: isolate test so that it can be guaranteed that the 503 will trigger xfer retries
|
||||
//c.Assert(out, checker.Contains, "Retrying")
|
||||
//c.Assert(out, checker.Not(checker.Contains), "Retrying in 15")
|
||||
split := strings.Split(out, "\n")
|
||||
c.Assert(split[len(split)-2], check.Equals, "toomanyrequests: out of tokens")
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnparsable(c *check.C) {
|
||||
ts := getTestTokenService(http.StatusForbidden, `no way`, 0)
|
||||
defer ts.Close()
|
||||
s.setupRegistryWithTokenService(c, ts.URL)
|
||||
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||
dockerCmd(c, "tag", "busybox", repoName)
|
||||
out, _, err := dockerCmdWithError("push", repoName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Not(checker.Contains), "Retrying")
|
||||
split := strings.Split(out, "\n")
|
||||
c.Assert(split[len(split)-2], checker.Contains, "error parsing HTTP 403 response body: ")
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseNoToken(c *check.C) {
|
||||
ts := getTestTokenService(http.StatusOK, `{"something": "wrong"}`, 0)
|
||||
defer ts.Close()
|
||||
s.setupRegistryWithTokenService(c, ts.URL)
|
||||
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
|
||||
dockerCmd(c, "tag", "busybox", repoName)
|
||||
out, _, err := dockerCmdWithError("push", repoName)
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Not(checker.Contains), "Retrying")
|
||||
split := strings.Split(out, "\n")
|
||||
c.Assert(split[len(split)-2], check.Equals, "authorization server did not include a token in the response")
|
||||
}
|
103
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_registry_user_agent_test.go
generated
vendored
Normal file
103
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_registry_user_agent_test.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"github.com/docker/docker/internal/test/registry"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// unescapeBackslashSemicolonParens unescapes \;()
|
||||
func unescapeBackslashSemicolonParens(s string) string {
|
||||
re := regexp.MustCompile(`\\;`)
|
||||
ret := re.ReplaceAll([]byte(s), []byte(";"))
|
||||
|
||||
re = regexp.MustCompile(`\\\(`)
|
||||
ret = re.ReplaceAll([]byte(ret), []byte("("))
|
||||
|
||||
re = regexp.MustCompile(`\\\)`)
|
||||
ret = re.ReplaceAll([]byte(ret), []byte(")"))
|
||||
|
||||
re = regexp.MustCompile(`\\\\`)
|
||||
ret = re.ReplaceAll([]byte(ret), []byte(`\`))
|
||||
|
||||
return string(ret)
|
||||
}
|
||||
|
||||
func regexpCheckUA(c *check.C, ua string) {
|
||||
re := regexp.MustCompile("(?P<dockerUA>.+) UpstreamClient(?P<upstreamUA>.+)")
|
||||
substrArr := re.FindStringSubmatch(ua)
|
||||
|
||||
c.Assert(substrArr, check.HasLen, 3, check.Commentf("Expected 'UpstreamClient()' with upstream client UA"))
|
||||
dockerUA := substrArr[1]
|
||||
upstreamUAEscaped := substrArr[2]
|
||||
|
||||
// check dockerUA looks correct
|
||||
reDockerUA := regexp.MustCompile("^docker/[0-9A-Za-z+]")
|
||||
bMatchDockerUA := reDockerUA.MatchString(dockerUA)
|
||||
c.Assert(bMatchDockerUA, check.Equals, true, check.Commentf("Docker Engine User-Agent malformed"))
|
||||
|
||||
// check upstreamUA looks correct
|
||||
// Expecting something like: Docker-Client/1.11.0-dev (linux)
|
||||
upstreamUA := unescapeBackslashSemicolonParens(upstreamUAEscaped)
|
||||
reUpstreamUA := regexp.MustCompile("^\\(Docker-Client/[0-9A-Za-z+]")
|
||||
bMatchUpstreamUA := reUpstreamUA.MatchString(upstreamUA)
|
||||
c.Assert(bMatchUpstreamUA, check.Equals, true, check.Commentf("(Upstream) Docker Client User-Agent malformed"))
|
||||
}
|
||||
|
||||
// registerUserAgentHandler registers a handler for the `/v2/*` endpoint.
|
||||
// Note that a 404 is returned to prevent the client to proceed.
|
||||
// We are only checking if the client sent a valid User Agent string along
|
||||
// with the request.
|
||||
func registerUserAgentHandler(reg *registry.Mock, result *string) {
|
||||
reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(404)
|
||||
w.Write([]byte(`{"errors":[{"code": "UNSUPPORTED","message": "this is a mock registry"}]}`))
|
||||
var ua string
|
||||
for k, v := range r.Header {
|
||||
if k == "User-Agent" {
|
||||
ua = v[0]
|
||||
}
|
||||
}
|
||||
*result = ua
|
||||
})
|
||||
}
|
||||
|
||||
// TestUserAgentPassThrough verifies that when an image is pulled from
|
||||
// a registry, the registry should see a User-Agent string of the form
|
||||
// [docker engine UA] UpstreamClientSTREAM-CLIENT([client UA])
|
||||
func (s *DockerRegistrySuite) TestUserAgentPassThrough(c *check.C) {
|
||||
var ua string
|
||||
|
||||
reg, err := registry.NewMock(c)
|
||||
defer reg.Close()
|
||||
c.Assert(err, check.IsNil)
|
||||
registerUserAgentHandler(reg, &ua)
|
||||
repoName := fmt.Sprintf("%s/busybox", reg.URL())
|
||||
|
||||
s.d.StartWithBusybox(c, "--insecure-registry", reg.URL())
|
||||
|
||||
tmp, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, check.IsNil)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
dockerfile, err := makefile(tmp, fmt.Sprintf("FROM %s", repoName))
|
||||
c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile"))
|
||||
|
||||
s.d.Cmd("build", "--file", dockerfile, tmp)
|
||||
regexpCheckUA(c, ua)
|
||||
|
||||
s.d.Cmd("login", "-u", "richard", "-p", "testtest", reg.URL())
|
||||
regexpCheckUA(c, ua)
|
||||
|
||||
s.d.Cmd("pull", repoName)
|
||||
regexpCheckUA(c, ua)
|
||||
|
||||
s.d.Cmd("tag", "busybox", repoName)
|
||||
s.d.Cmd("push", repoName)
|
||||
regexpCheckUA(c, ua)
|
||||
}
|
310
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_restart_test.go
generated
vendored
Normal file
310
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_restart_test.go
generated
vendored
Normal file
|
@ -0,0 +1,310 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestRestartStoppedContainer(c *check.C) {
|
||||
dockerCmd(c, "run", "--name=test", "busybox", "echo", "foobar")
|
||||
cleanedContainerID := getIDByName(c, "test")
|
||||
|
||||
out, _ := dockerCmd(c, "logs", cleanedContainerID)
|
||||
c.Assert(out, checker.Equals, "foobar\n")
|
||||
|
||||
dockerCmd(c, "restart", cleanedContainerID)
|
||||
|
||||
// Wait until the container has stopped
|
||||
err := waitInspect(cleanedContainerID, "{{.State.Running}}", "false", 20*time.Second)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "logs", cleanedContainerID)
|
||||
c.Assert(out, checker.Equals, "foobar\nfoobar\n")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRestartRunningContainer(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "echo foobar && sleep 30 && echo 'should not print this'")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
c.Assert(waitRun(cleanedContainerID), checker.IsNil)
|
||||
|
||||
getLogs := func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
out, _ := dockerCmd(c, "logs", cleanedContainerID)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Wait 10 seconds for the 'echo' to appear in the logs
|
||||
waitAndAssert(c, 10*time.Second, getLogs, checker.Equals, "foobar\n")
|
||||
|
||||
dockerCmd(c, "restart", "-t", "1", cleanedContainerID)
|
||||
c.Assert(waitRun(cleanedContainerID), checker.IsNil)
|
||||
|
||||
// Wait 10 seconds for first 'echo' appear (again) in the logs
|
||||
waitAndAssert(c, 10*time.Second, getLogs, checker.Equals, "foobar\nfoobar\n")
|
||||
}
|
||||
|
||||
// Test that restarting a container with a volume does not create a new volume on restart. Regression test for #819.
|
||||
func (s *DockerSuite) TestRestartWithVolumes(c *check.C) {
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
out := runSleepingContainer(c, "-d", "-v", prefix+slash+"test")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
out, err := inspectFilter(cleanedContainerID, "len .Mounts")
|
||||
c.Assert(err, check.IsNil, check.Commentf("failed to inspect %s: %s", cleanedContainerID, out))
|
||||
out = strings.Trim(out, " \n\r")
|
||||
c.Assert(out, checker.Equals, "1")
|
||||
|
||||
source, err := inspectMountSourceField(cleanedContainerID, prefix+slash+"test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "restart", cleanedContainerID)
|
||||
|
||||
out, err = inspectFilter(cleanedContainerID, "len .Mounts")
|
||||
c.Assert(err, check.IsNil, check.Commentf("failed to inspect %s: %s", cleanedContainerID, out))
|
||||
out = strings.Trim(out, " \n\r")
|
||||
c.Assert(out, checker.Equals, "1")
|
||||
|
||||
sourceAfterRestart, err := inspectMountSourceField(cleanedContainerID, prefix+slash+"test")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(source, checker.Equals, sourceAfterRestart)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRestartDisconnectedContainer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace, NotArm)
|
||||
|
||||
// Run a container on the default bridge network
|
||||
out, _ := dockerCmd(c, "run", "-d", "--name", "c0", "busybox", "top")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(cleanedContainerID), checker.IsNil)
|
||||
|
||||
// Disconnect the container from the network
|
||||
out, err := dockerCmd(c, "network", "disconnect", "bridge", "c0")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
|
||||
// Restart the container
|
||||
dockerCmd(c, "restart", "c0")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRestartPolicyNO(c *check.C) {
|
||||
out, _ := dockerCmd(c, "create", "--restart=no", "busybox")
|
||||
|
||||
id := strings.TrimSpace(string(out))
|
||||
name := inspectField(c, id, "HostConfig.RestartPolicy.Name")
|
||||
c.Assert(name, checker.Equals, "no")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRestartPolicyAlways(c *check.C) {
|
||||
out, _ := dockerCmd(c, "create", "--restart=always", "busybox")
|
||||
|
||||
id := strings.TrimSpace(string(out))
|
||||
name := inspectField(c, id, "HostConfig.RestartPolicy.Name")
|
||||
c.Assert(name, checker.Equals, "always")
|
||||
|
||||
MaximumRetryCount := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount")
|
||||
|
||||
// MaximumRetryCount=0 if the restart policy is always
|
||||
c.Assert(MaximumRetryCount, checker.Equals, "0")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRestartPolicyOnFailure(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("create", "--restart=on-failure:-1", "busybox")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "maximum retry count cannot be negative")
|
||||
|
||||
out, _ = dockerCmd(c, "create", "--restart=on-failure:1", "busybox")
|
||||
|
||||
id := strings.TrimSpace(string(out))
|
||||
name := inspectField(c, id, "HostConfig.RestartPolicy.Name")
|
||||
maxRetry := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount")
|
||||
|
||||
c.Assert(name, checker.Equals, "on-failure")
|
||||
c.Assert(maxRetry, checker.Equals, "1")
|
||||
|
||||
out, _ = dockerCmd(c, "create", "--restart=on-failure:0", "busybox")
|
||||
|
||||
id = strings.TrimSpace(string(out))
|
||||
name = inspectField(c, id, "HostConfig.RestartPolicy.Name")
|
||||
maxRetry = inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount")
|
||||
|
||||
c.Assert(name, checker.Equals, "on-failure")
|
||||
c.Assert(maxRetry, checker.Equals, "0")
|
||||
|
||||
out, _ = dockerCmd(c, "create", "--restart=on-failure", "busybox")
|
||||
|
||||
id = strings.TrimSpace(string(out))
|
||||
name = inspectField(c, id, "HostConfig.RestartPolicy.Name")
|
||||
maxRetry = inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount")
|
||||
|
||||
c.Assert(name, checker.Equals, "on-failure")
|
||||
c.Assert(maxRetry, checker.Equals, "0")
|
||||
}
|
||||
|
||||
// a good container with --restart=on-failure:3
|
||||
// MaximumRetryCount!=0; RestartCount=0
|
||||
func (s *DockerSuite) TestRestartContainerwithGoodContainer(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "true")
|
||||
|
||||
id := strings.TrimSpace(string(out))
|
||||
err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 30*time.Second)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
count := inspectField(c, id, "RestartCount")
|
||||
c.Assert(count, checker.Equals, "0")
|
||||
|
||||
MaximumRetryCount := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount")
|
||||
c.Assert(MaximumRetryCount, checker.Equals, "3")
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRestartContainerSuccess(c *check.C) {
|
||||
testRequires(c, SameHostDaemon)
|
||||
|
||||
out := runSleepingContainer(c, "-d", "--restart=always")
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), check.IsNil)
|
||||
|
||||
pidStr := inspectField(c, id, "State.Pid")
|
||||
|
||||
pid, err := strconv.Atoi(pidStr)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
p, err := os.FindProcess(pid)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(p, check.NotNil)
|
||||
|
||||
err = p.Kill()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = waitInspect(id, "{{.RestartCount}}", "1", 30*time.Second)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = waitInspect(id, "{{.State.Status}}", "running", 30*time.Second)
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRestartWithPolicyUserDefinedNetwork(c *check.C) {
|
||||
// TODO Windows. This may be portable following HNS integration post TP5.
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace, NotArm)
|
||||
dockerCmd(c, "network", "create", "-d", "bridge", "udNet")
|
||||
|
||||
dockerCmd(c, "run", "-d", "--net=udNet", "--name=first", "busybox", "top")
|
||||
c.Assert(waitRun("first"), check.IsNil)
|
||||
|
||||
dockerCmd(c, "run", "-d", "--restart=always", "--net=udNet", "--name=second",
|
||||
"--link=first:foo", "busybox", "top")
|
||||
c.Assert(waitRun("second"), check.IsNil)
|
||||
|
||||
// ping to first and its alias foo must succeed
|
||||
_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
|
||||
c.Assert(err, check.IsNil)
|
||||
_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// Now kill the second container and let the restart policy kick in
|
||||
pidStr := inspectField(c, "second", "State.Pid")
|
||||
|
||||
pid, err := strconv.Atoi(pidStr)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
p, err := os.FindProcess(pid)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(p, check.NotNil)
|
||||
|
||||
err = p.Kill()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = waitInspect("second", "{{.RestartCount}}", "1", 5*time.Second)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = waitInspect("second", "{{.State.Status}}", "running", 5*time.Second)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// ping to first and its alias foo must still succeed
|
||||
_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
|
||||
c.Assert(err, check.IsNil)
|
||||
_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRestartPolicyAfterRestart(c *check.C) {
|
||||
testRequires(c, SameHostDaemon)
|
||||
|
||||
out := runSleepingContainer(c, "-d", "--restart=always")
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), check.IsNil)
|
||||
|
||||
dockerCmd(c, "restart", id)
|
||||
|
||||
c.Assert(waitRun(id), check.IsNil)
|
||||
|
||||
pidStr := inspectField(c, id, "State.Pid")
|
||||
|
||||
pid, err := strconv.Atoi(pidStr)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
p, err := os.FindProcess(pid)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(p, check.NotNil)
|
||||
|
||||
err = p.Kill()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = waitInspect(id, "{{.RestartCount}}", "1", 30*time.Second)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = waitInspect(id, "{{.State.Status}}", "running", 30*time.Second)
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRestartContainerwithRestartPolicy(c *check.C) {
|
||||
out1, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "false")
|
||||
out2, _ := dockerCmd(c, "run", "-d", "--restart=always", "busybox", "false")
|
||||
|
||||
id1 := strings.TrimSpace(string(out1))
|
||||
id2 := strings.TrimSpace(string(out2))
|
||||
waitTimeout := 15 * time.Second
|
||||
if testEnv.OSType == "windows" {
|
||||
waitTimeout = 150 * time.Second
|
||||
}
|
||||
err := waitInspect(id1, "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTimeout)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "restart", id1)
|
||||
dockerCmd(c, "restart", id2)
|
||||
|
||||
// Make sure we can stop/start (regression test from a705e166cf3bcca62543150c2b3f9bfeae45ecfa)
|
||||
dockerCmd(c, "stop", id1)
|
||||
dockerCmd(c, "stop", id2)
|
||||
dockerCmd(c, "start", id1)
|
||||
dockerCmd(c, "start", id2)
|
||||
|
||||
// Kill the containers, making sure the are stopped at the end of the test
|
||||
dockerCmd(c, "kill", id1)
|
||||
dockerCmd(c, "kill", id2)
|
||||
err = waitInspect(id1, "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTimeout)
|
||||
c.Assert(err, checker.IsNil)
|
||||
err = waitInspect(id2, "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTimeout)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRestartAutoRemoveContainer(c *check.C) {
|
||||
out := runSleepingContainer(c, "--rm")
|
||||
|
||||
id := strings.TrimSpace(string(out))
|
||||
dockerCmd(c, "restart", id)
|
||||
err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 15*time.Second)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "ps")
|
||||
c.Assert(out, checker.Contains, id[:12], check.Commentf("container should be restarted instead of removed: %v", out))
|
||||
|
||||
// Kill the container to make sure it will be removed
|
||||
dockerCmd(c, "kill", id)
|
||||
}
|
338
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_rmi_test.go
generated
vendored
Normal file
338
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_rmi_test.go
generated
vendored
Normal file
|
@ -0,0 +1,338 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestRmiWithContainerFails(c *check.C) {
|
||||
errSubstr := "is using it"
|
||||
|
||||
// create a container
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
// try to delete the image
|
||||
out, _, err := dockerCmdWithError("rmi", "busybox")
|
||||
// Container is using image, should not be able to rmi
|
||||
c.Assert(err, checker.NotNil)
|
||||
// Container is using image, error message should contain errSubstr
|
||||
c.Assert(out, checker.Contains, errSubstr, check.Commentf("Container: %q", cleanedContainerID))
|
||||
|
||||
// make sure it didn't delete the busybox name
|
||||
images, _ := dockerCmd(c, "images")
|
||||
// The name 'busybox' should not have been removed from images
|
||||
c.Assert(images, checker.Contains, "busybox")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmiTag(c *check.C) {
|
||||
imagesBefore, _ := dockerCmd(c, "images", "-a")
|
||||
dockerCmd(c, "tag", "busybox", "utest:tag1")
|
||||
dockerCmd(c, "tag", "busybox", "utest/docker:tag2")
|
||||
dockerCmd(c, "tag", "busybox", "utest:5000/docker:tag3")
|
||||
{
|
||||
imagesAfter, _ := dockerCmd(c, "images", "-a")
|
||||
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+3, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter))
|
||||
}
|
||||
dockerCmd(c, "rmi", "utest/docker:tag2")
|
||||
{
|
||||
imagesAfter, _ := dockerCmd(c, "images", "-a")
|
||||
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+2, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter))
|
||||
}
|
||||
dockerCmd(c, "rmi", "utest:5000/docker:tag3")
|
||||
{
|
||||
imagesAfter, _ := dockerCmd(c, "images", "-a")
|
||||
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+1, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter))
|
||||
|
||||
}
|
||||
dockerCmd(c, "rmi", "utest:tag1")
|
||||
{
|
||||
imagesAfter, _ := dockerCmd(c, "images", "-a")
|
||||
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n"), check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmiImgIDMultipleTag(c *check.C) {
|
||||
out := cli.DockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir '/busybox-one'").Combined()
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
// Wait for it to exit as cannot commit a running container on Windows, and
|
||||
// it will take a few seconds to exit
|
||||
if testEnv.OSType == "windows" {
|
||||
cli.WaitExited(c, containerID, 60*time.Second)
|
||||
}
|
||||
|
||||
cli.DockerCmd(c, "commit", containerID, "busybox-one")
|
||||
|
||||
imagesBefore := cli.DockerCmd(c, "images", "-a").Combined()
|
||||
cli.DockerCmd(c, "tag", "busybox-one", "busybox-one:tag1")
|
||||
cli.DockerCmd(c, "tag", "busybox-one", "busybox-one:tag2")
|
||||
|
||||
imagesAfter := cli.DockerCmd(c, "images", "-a").Combined()
|
||||
// tag busybox to create 2 more images with same imageID
|
||||
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+2, check.Commentf("docker images shows: %q\n", imagesAfter))
|
||||
|
||||
imgID := inspectField(c, "busybox-one:tag1", "Id")
|
||||
|
||||
// run a container with the image
|
||||
out = runSleepingContainerInImage(c, "busybox-one")
|
||||
containerID = strings.TrimSpace(out)
|
||||
|
||||
// first checkout without force it fails
|
||||
// rmi tagged in multiple repos should have failed without force
|
||||
cli.Docker(cli.Args("rmi", imgID)).Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: fmt.Sprintf("conflict: unable to delete %s (cannot be forced) - image is being used by running container %s", stringid.TruncateID(imgID), stringid.TruncateID(containerID)),
|
||||
})
|
||||
|
||||
cli.DockerCmd(c, "stop", containerID)
|
||||
cli.DockerCmd(c, "rmi", "-f", imgID)
|
||||
|
||||
imagesAfter = cli.DockerCmd(c, "images", "-a").Combined()
|
||||
// rmi -f failed, image still exists
|
||||
c.Assert(imagesAfter, checker.Not(checker.Contains), imgID[:12], check.Commentf("ImageID:%q; ImagesAfter: %q", imgID, imagesAfter))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmiImgIDForce(c *check.C) {
|
||||
out := cli.DockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir '/busybox-test'").Combined()
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
// Wait for it to exit as cannot commit a running container on Windows, and
|
||||
// it will take a few seconds to exit
|
||||
if testEnv.OSType == "windows" {
|
||||
cli.WaitExited(c, containerID, 60*time.Second)
|
||||
}
|
||||
|
||||
cli.DockerCmd(c, "commit", containerID, "busybox-test")
|
||||
|
||||
imagesBefore := cli.DockerCmd(c, "images", "-a").Combined()
|
||||
cli.DockerCmd(c, "tag", "busybox-test", "utest:tag1")
|
||||
cli.DockerCmd(c, "tag", "busybox-test", "utest:tag2")
|
||||
cli.DockerCmd(c, "tag", "busybox-test", "utest/docker:tag3")
|
||||
cli.DockerCmd(c, "tag", "busybox-test", "utest:5000/docker:tag4")
|
||||
{
|
||||
imagesAfter := cli.DockerCmd(c, "images", "-a").Combined()
|
||||
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+4, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter))
|
||||
}
|
||||
imgID := inspectField(c, "busybox-test", "Id")
|
||||
|
||||
// first checkout without force it fails
|
||||
cli.Docker(cli.Args("rmi", imgID)).Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: "(must be forced) - image is referenced in multiple repositories",
|
||||
})
|
||||
|
||||
cli.DockerCmd(c, "rmi", "-f", imgID)
|
||||
{
|
||||
imagesAfter := cli.DockerCmd(c, "images", "-a").Combined()
|
||||
// rmi failed, image still exists
|
||||
c.Assert(imagesAfter, checker.Not(checker.Contains), imgID[:12])
|
||||
}
|
||||
}
|
||||
|
||||
// See https://github.com/docker/docker/issues/14116
|
||||
func (s *DockerSuite) TestRmiImageIDForceWithRunningContainersAndMultipleTags(c *check.C) {
|
||||
dockerfile := "FROM busybox\nRUN echo test 14116\n"
|
||||
buildImageSuccessfully(c, "test-14116", build.WithDockerfile(dockerfile))
|
||||
imgID := getIDByName(c, "test-14116")
|
||||
|
||||
newTag := "newtag"
|
||||
dockerCmd(c, "tag", imgID, newTag)
|
||||
runSleepingContainerInImage(c, imgID)
|
||||
|
||||
out, _, err := dockerCmdWithError("rmi", "-f", imgID)
|
||||
// rmi -f should not delete image with running containers
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "(cannot be forced) - image is being used by running container")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmiTagWithExistingContainers(c *check.C) {
|
||||
container := "test-delete-tag"
|
||||
newtag := "busybox:newtag"
|
||||
bb := "busybox:latest"
|
||||
dockerCmd(c, "tag", bb, newtag)
|
||||
|
||||
dockerCmd(c, "run", "--name", container, bb, "/bin/true")
|
||||
|
||||
out, _ := dockerCmd(c, "rmi", newtag)
|
||||
c.Assert(strings.Count(out, "Untagged: "), checker.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmiForceWithExistingContainers(c *check.C) {
|
||||
image := "busybox-clone"
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "build", "--no-cache", "-t", image, "-"},
|
||||
Stdin: strings.NewReader(`FROM busybox
|
||||
MAINTAINER foo`),
|
||||
}).Assert(c, icmd.Success)
|
||||
|
||||
dockerCmd(c, "run", "--name", "test-force-rmi", image, "/bin/true")
|
||||
|
||||
dockerCmd(c, "rmi", "-f", image)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmiWithMultipleRepositories(c *check.C) {
|
||||
newRepo := "127.0.0.1:5000/busybox"
|
||||
oldRepo := "busybox"
|
||||
newTag := "busybox:test"
|
||||
dockerCmd(c, "tag", oldRepo, newRepo)
|
||||
|
||||
dockerCmd(c, "run", "--name", "test", oldRepo, "touch", "/abcd")
|
||||
|
||||
dockerCmd(c, "commit", "test", newTag)
|
||||
|
||||
out, _ := dockerCmd(c, "rmi", newTag)
|
||||
c.Assert(out, checker.Contains, "Untagged: "+newTag)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmiForceWithMultipleRepositories(c *check.C) {
|
||||
imageName := "rmiimage"
|
||||
tag1 := imageName + ":tag1"
|
||||
tag2 := imageName + ":tag2"
|
||||
|
||||
buildImageSuccessfully(c, tag1, build.WithDockerfile(`FROM busybox
|
||||
MAINTAINER "docker"`))
|
||||
dockerCmd(c, "tag", tag1, tag2)
|
||||
|
||||
out, _ := dockerCmd(c, "rmi", "-f", tag2)
|
||||
c.Assert(out, checker.Contains, "Untagged: "+tag2)
|
||||
c.Assert(out, checker.Not(checker.Contains), "Untagged: "+tag1)
|
||||
|
||||
// Check built image still exists
|
||||
images, _ := dockerCmd(c, "images", "-a")
|
||||
c.Assert(images, checker.Contains, imageName, check.Commentf("Built image missing %q; Images: %q", imageName, images))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmiBlank(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("rmi", " ")
|
||||
// Should have failed to delete ' ' image
|
||||
c.Assert(err, checker.NotNil)
|
||||
// Wrong error message generated
|
||||
c.Assert(out, checker.Not(checker.Contains), "no such id", check.Commentf("out: %s", out))
|
||||
// Expected error message not generated
|
||||
c.Assert(out, checker.Contains, "image name cannot be blank", check.Commentf("out: %s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmiContainerImageNotFound(c *check.C) {
|
||||
// Build 2 images for testing.
|
||||
imageNames := []string{"test1", "test2"}
|
||||
imageIds := make([]string, 2)
|
||||
for i, name := range imageNames {
|
||||
dockerfile := fmt.Sprintf("FROM busybox\nMAINTAINER %s\nRUN echo %s\n", name, name)
|
||||
buildImageSuccessfully(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
|
||||
id := getIDByName(c, name)
|
||||
imageIds[i] = id
|
||||
}
|
||||
|
||||
// Create a long-running container.
|
||||
runSleepingContainerInImage(c, imageNames[0])
|
||||
|
||||
// Create a stopped container, and then force remove its image.
|
||||
dockerCmd(c, "run", imageNames[1], "true")
|
||||
dockerCmd(c, "rmi", "-f", imageIds[1])
|
||||
|
||||
// Try to remove the image of the running container and see if it fails as expected.
|
||||
out, _, err := dockerCmdWithError("rmi", "-f", imageIds[0])
|
||||
// The image of the running container should not be removed.
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "image is being used by running container", check.Commentf("out: %s", out))
|
||||
}
|
||||
|
||||
// #13422
|
||||
func (s *DockerSuite) TestRmiUntagHistoryLayer(c *check.C) {
|
||||
image := "tmp1"
|
||||
// Build an image for testing.
|
||||
dockerfile := `FROM busybox
|
||||
MAINTAINER foo
|
||||
RUN echo 0 #layer0
|
||||
RUN echo 1 #layer1
|
||||
RUN echo 2 #layer2
|
||||
`
|
||||
buildImageSuccessfully(c, image, build.WithoutCache, build.WithDockerfile(dockerfile))
|
||||
out, _ := dockerCmd(c, "history", "-q", image)
|
||||
ids := strings.Split(out, "\n")
|
||||
idToTag := ids[2]
|
||||
|
||||
// Tag layer0 to "tmp2".
|
||||
newTag := "tmp2"
|
||||
dockerCmd(c, "tag", idToTag, newTag)
|
||||
// Create a container based on "tmp1".
|
||||
dockerCmd(c, "run", "-d", image, "true")
|
||||
|
||||
// See if the "tmp2" can be untagged.
|
||||
out, _ = dockerCmd(c, "rmi", newTag)
|
||||
// Expected 1 untagged entry
|
||||
c.Assert(strings.Count(out, "Untagged: "), checker.Equals, 1, check.Commentf("out: %s", out))
|
||||
|
||||
// Now let's add the tag again and create a container based on it.
|
||||
dockerCmd(c, "tag", idToTag, newTag)
|
||||
out, _ = dockerCmd(c, "run", "-d", newTag, "true")
|
||||
cid := strings.TrimSpace(out)
|
||||
|
||||
// At this point we have 2 containers, one based on layer2 and another based on layer0.
|
||||
// Try to untag "tmp2" without the -f flag.
|
||||
out, _, err := dockerCmdWithError("rmi", newTag)
|
||||
// should not be untagged without the -f flag
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, cid[:12])
|
||||
c.Assert(out, checker.Contains, "(must force)")
|
||||
|
||||
// Add the -f flag and test again.
|
||||
out, _ = dockerCmd(c, "rmi", "-f", newTag)
|
||||
// should be allowed to untag with the -f flag
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("Untagged: %s:latest", newTag))
|
||||
}
|
||||
|
||||
func (*DockerSuite) TestRmiParentImageFail(c *check.C) {
|
||||
buildImageSuccessfully(c, "test", build.WithDockerfile(`
|
||||
FROM busybox
|
||||
RUN echo hello`))
|
||||
|
||||
id := inspectField(c, "busybox", "ID")
|
||||
out, _, err := dockerCmdWithError("rmi", id)
|
||||
c.Assert(err, check.NotNil)
|
||||
if !strings.Contains(out, "image has dependent child images") {
|
||||
c.Fatalf("rmi should have failed because it's a parent image, got %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRmiWithParentInUse(c *check.C) {
|
||||
out, _ := dockerCmd(c, "create", "busybox")
|
||||
cID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "commit", cID)
|
||||
imageID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "create", imageID)
|
||||
cID = strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "commit", cID)
|
||||
imageID = strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "rmi", imageID)
|
||||
}
|
||||
|
||||
// #18873
|
||||
func (s *DockerSuite) TestRmiByIDHardConflict(c *check.C) {
|
||||
dockerCmd(c, "create", "busybox")
|
||||
|
||||
imgID := inspectField(c, "busybox:latest", "Id")
|
||||
|
||||
_, _, err := dockerCmdWithError("rmi", imgID[:12])
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
// check that tag was not removed
|
||||
imgID2 := inspectField(c, "busybox:latest", "Id")
|
||||
c.Assert(imgID, checker.Equals, imgID2)
|
||||
}
|
4541
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_run_test.go
generated
vendored
Normal file
4541
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_run_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1585
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_run_unix_test.go
generated
vendored
Normal file
1585
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_run_unix_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
405
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_save_load_test.go
generated
vendored
Normal file
405
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_save_load_test.go
generated
vendored
Normal file
|
@ -0,0 +1,405 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// save a repo using gz compression and try to load it using stdout
|
||||
func (s *DockerSuite) TestSaveXzAndLoadRepoStdout(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "test-save-xz-and-load-repo-stdout"
|
||||
dockerCmd(c, "run", "--name", name, "busybox", "true")
|
||||
|
||||
repoName := "foobar-save-load-test-xz-gz"
|
||||
out, _ := dockerCmd(c, "commit", name, repoName)
|
||||
|
||||
dockerCmd(c, "inspect", repoName)
|
||||
|
||||
repoTarball, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "save", repoName),
|
||||
exec.Command("xz", "-c"),
|
||||
exec.Command("gzip", "-c"))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save repo: %v %v", out, err))
|
||||
deleteImages(repoName)
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "load"},
|
||||
Stdin: strings.NewReader(repoTarball),
|
||||
}).Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
})
|
||||
|
||||
after, _, err := dockerCmdWithError("inspect", repoName)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("the repo should not exist: %v", after))
|
||||
}
|
||||
|
||||
// save a repo using xz+gz compression and try to load it using stdout
|
||||
func (s *DockerSuite) TestSaveXzGzAndLoadRepoStdout(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "test-save-xz-gz-and-load-repo-stdout"
|
||||
dockerCmd(c, "run", "--name", name, "busybox", "true")
|
||||
|
||||
repoName := "foobar-save-load-test-xz-gz"
|
||||
dockerCmd(c, "commit", name, repoName)
|
||||
|
||||
dockerCmd(c, "inspect", repoName)
|
||||
|
||||
out, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "save", repoName),
|
||||
exec.Command("xz", "-c"),
|
||||
exec.Command("gzip", "-c"))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save repo: %v %v", out, err))
|
||||
|
||||
deleteImages(repoName)
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "load"},
|
||||
Stdin: strings.NewReader(out),
|
||||
}).Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
})
|
||||
|
||||
after, _, err := dockerCmdWithError("inspect", repoName)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("the repo should not exist: %v", after))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSaveSingleTag(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
repoName := "foobar-save-single-tag-test"
|
||||
dockerCmd(c, "tag", "busybox:latest", fmt.Sprintf("%v:latest", repoName))
|
||||
|
||||
out, _ := dockerCmd(c, "images", "-q", "--no-trunc", repoName)
|
||||
cleanedImageID := strings.TrimSpace(out)
|
||||
|
||||
out, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "save", fmt.Sprintf("%v:latest", repoName)),
|
||||
exec.Command("tar", "t"),
|
||||
exec.Command("grep", "-E", fmt.Sprintf("(^repositories$|%v)", cleanedImageID)))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save repo with image ID and 'repositories' file: %s, %v", out, err))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSaveCheckTimes(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
repoName := "busybox:latest"
|
||||
out, _ := dockerCmd(c, "inspect", repoName)
|
||||
var data []struct {
|
||||
ID string
|
||||
Created time.Time
|
||||
}
|
||||
err := json.Unmarshal([]byte(out), &data)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to marshal from %q: err %v", repoName, err))
|
||||
c.Assert(len(data), checker.Not(checker.Equals), 0, check.Commentf("failed to marshal the data from %q", repoName))
|
||||
tarTvTimeFormat := "2006-01-02 15:04"
|
||||
out, err = RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "save", repoName),
|
||||
exec.Command("tar", "tv"),
|
||||
exec.Command("grep", "-E", fmt.Sprintf("%s %s", data[0].Created.Format(tarTvTimeFormat), digest.Digest(data[0].ID).Hex())))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save repo with image ID and 'repositories' file: %s, %v", out, err))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSaveImageId(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
repoName := "foobar-save-image-id-test"
|
||||
dockerCmd(c, "tag", "emptyfs:latest", fmt.Sprintf("%v:latest", repoName))
|
||||
|
||||
out, _ := dockerCmd(c, "images", "-q", "--no-trunc", repoName)
|
||||
cleanedLongImageID := strings.TrimPrefix(strings.TrimSpace(out), "sha256:")
|
||||
|
||||
out, _ = dockerCmd(c, "images", "-q", repoName)
|
||||
cleanedShortImageID := strings.TrimSpace(out)
|
||||
|
||||
// Make sure IDs are not empty
|
||||
c.Assert(cleanedLongImageID, checker.Not(check.Equals), "", check.Commentf("Id should not be empty."))
|
||||
c.Assert(cleanedShortImageID, checker.Not(check.Equals), "", check.Commentf("Id should not be empty."))
|
||||
|
||||
saveCmd := exec.Command(dockerBinary, "save", cleanedShortImageID)
|
||||
tarCmd := exec.Command("tar", "t")
|
||||
|
||||
var err error
|
||||
tarCmd.Stdin, err = saveCmd.StdoutPipe()
|
||||
c.Assert(err, checker.IsNil, check.Commentf("cannot set stdout pipe for tar: %v", err))
|
||||
grepCmd := exec.Command("grep", cleanedLongImageID)
|
||||
grepCmd.Stdin, err = tarCmd.StdoutPipe()
|
||||
c.Assert(err, checker.IsNil, check.Commentf("cannot set stdout pipe for grep: %v", err))
|
||||
|
||||
c.Assert(tarCmd.Start(), checker.IsNil, check.Commentf("tar failed with error: %v", err))
|
||||
c.Assert(saveCmd.Start(), checker.IsNil, check.Commentf("docker save failed with error: %v", err))
|
||||
defer func() {
|
||||
saveCmd.Wait()
|
||||
tarCmd.Wait()
|
||||
dockerCmd(c, "rmi", repoName)
|
||||
}()
|
||||
|
||||
out, _, err = runCommandWithOutput(grepCmd)
|
||||
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save repo with image ID: %s, %v", out, err))
|
||||
}
|
||||
|
||||
// save a repo and try to load it using flags
|
||||
func (s *DockerSuite) TestSaveAndLoadRepoFlags(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "test-save-and-load-repo-flags"
|
||||
dockerCmd(c, "run", "--name", name, "busybox", "true")
|
||||
|
||||
repoName := "foobar-save-load-test"
|
||||
|
||||
deleteImages(repoName)
|
||||
dockerCmd(c, "commit", name, repoName)
|
||||
|
||||
before, _ := dockerCmd(c, "inspect", repoName)
|
||||
|
||||
out, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "save", repoName),
|
||||
exec.Command(dockerBinary, "load"))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save and load repo: %s, %v", out, err))
|
||||
|
||||
after, _ := dockerCmd(c, "inspect", repoName)
|
||||
c.Assert(before, checker.Equals, after, check.Commentf("inspect is not the same after a save / load"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSaveWithNoExistImage(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
imgName := "foobar-non-existing-image"
|
||||
|
||||
out, _, err := dockerCmdWithError("save", "-o", "test-img.tar", imgName)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("save image should fail for non-existing image"))
|
||||
c.Assert(out, checker.Contains, fmt.Sprintf("No such image: %s", imgName))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSaveMultipleNames(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
repoName := "foobar-save-multi-name-test"
|
||||
|
||||
// Make one image
|
||||
dockerCmd(c, "tag", "emptyfs:latest", fmt.Sprintf("%v-one:latest", repoName))
|
||||
|
||||
// Make two images
|
||||
dockerCmd(c, "tag", "emptyfs:latest", fmt.Sprintf("%v-two:latest", repoName))
|
||||
|
||||
out, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "save", fmt.Sprintf("%v-one", repoName), fmt.Sprintf("%v-two:latest", repoName)),
|
||||
exec.Command("tar", "xO", "repositories"),
|
||||
exec.Command("grep", "-q", "-E", "(-one|-two)"),
|
||||
)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save multiple repos: %s, %v", out, err))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSaveRepoWithMultipleImages(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
makeImage := func(from string, tag string) string {
|
||||
var (
|
||||
out string
|
||||
)
|
||||
out, _ = dockerCmd(c, "run", "-d", from, "true")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "commit", cleanedContainerID, tag)
|
||||
imageID := strings.TrimSpace(out)
|
||||
return imageID
|
||||
}
|
||||
|
||||
repoName := "foobar-save-multi-images-test"
|
||||
tagFoo := repoName + ":foo"
|
||||
tagBar := repoName + ":bar"
|
||||
|
||||
idFoo := makeImage("busybox:latest", tagFoo)
|
||||
idBar := makeImage("busybox:latest", tagBar)
|
||||
|
||||
deleteImages(repoName)
|
||||
|
||||
// create the archive
|
||||
out, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "save", repoName, "busybox:latest"),
|
||||
exec.Command("tar", "t"))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save multiple images: %s, %v", out, err))
|
||||
|
||||
lines := strings.Split(strings.TrimSpace(out), "\n")
|
||||
var actual []string
|
||||
for _, l := range lines {
|
||||
if regexp.MustCompile("^[a-f0-9]{64}\\.json$").Match([]byte(l)) {
|
||||
actual = append(actual, strings.TrimSuffix(l, ".json"))
|
||||
}
|
||||
}
|
||||
|
||||
// make the list of expected layers
|
||||
out = inspectField(c, "busybox:latest", "Id")
|
||||
expected := []string{strings.TrimSpace(out), idFoo, idBar}
|
||||
|
||||
// prefixes are not in tar
|
||||
for i := range expected {
|
||||
expected[i] = digest.Digest(expected[i]).Hex()
|
||||
}
|
||||
|
||||
sort.Strings(actual)
|
||||
sort.Strings(expected)
|
||||
c.Assert(actual, checker.DeepEquals, expected, check.Commentf("archive does not contains the right layers: got %v, expected %v, output: %q", actual, expected, out))
|
||||
}
|
||||
|
||||
// Issue #6722 #5892 ensure directories are included in changes
|
||||
func (s *DockerSuite) TestSaveDirectoryPermissions(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
layerEntries := []string{"opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"}
|
||||
layerEntriesAUFS := []string{"./", ".wh..wh.aufs", ".wh..wh.orph/", ".wh..wh.plnk/", "opt/", "opt/a/", "opt/a/b/", "opt/a/b/c"}
|
||||
|
||||
name := "save-directory-permissions"
|
||||
tmpDir, err := ioutil.TempDir("", "save-layers-with-directories")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to create temporary directory: %s", err))
|
||||
extractionDirectory := filepath.Join(tmpDir, "image-extraction-dir")
|
||||
os.Mkdir(extractionDirectory, 0777)
|
||||
|
||||
defer os.RemoveAll(tmpDir)
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
|
||||
RUN adduser -D user && mkdir -p /opt/a/b && chown -R user:user /opt/a
|
||||
RUN touch /opt/a/b/c && chown user:user /opt/a/b/c`))
|
||||
|
||||
out, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "save", name),
|
||||
exec.Command("tar", "-xf", "-", "-C", extractionDirectory),
|
||||
)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save and extract image: %s", out))
|
||||
|
||||
dirs, err := ioutil.ReadDir(extractionDirectory)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to get a listing of the layer directories: %s", err))
|
||||
|
||||
found := false
|
||||
for _, entry := range dirs {
|
||||
var entriesSansDev []string
|
||||
if entry.IsDir() {
|
||||
layerPath := filepath.Join(extractionDirectory, entry.Name(), "layer.tar")
|
||||
|
||||
f, err := os.Open(layerPath)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to open %s: %s", layerPath, err))
|
||||
defer f.Close()
|
||||
|
||||
entries, err := listTar(f)
|
||||
for _, e := range entries {
|
||||
if !strings.Contains(e, "dev/") {
|
||||
entriesSansDev = append(entriesSansDev, e)
|
||||
}
|
||||
}
|
||||
c.Assert(err, checker.IsNil, check.Commentf("encountered error while listing tar entries: %s", err))
|
||||
|
||||
if reflect.DeepEqual(entriesSansDev, layerEntries) || reflect.DeepEqual(entriesSansDev, layerEntriesAUFS) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.Assert(found, checker.Equals, true, check.Commentf("failed to find the layer with the right content listing"))
|
||||
|
||||
}
|
||||
|
||||
func listTar(f io.Reader) ([]string, error) {
|
||||
tr := tar.NewReader(f)
|
||||
var entries []string
|
||||
|
||||
for {
|
||||
th, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
// end of tar archive
|
||||
return entries, nil
|
||||
}
|
||||
if err != nil {
|
||||
return entries, err
|
||||
}
|
||||
entries = append(entries, th.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Test loading a weird image where one of the layers is of zero size.
|
||||
// The layer.tar file is actually zero bytes, no padding or anything else.
|
||||
// See issue: 18170
|
||||
func (s *DockerSuite) TestLoadZeroSizeLayer(c *check.C) {
|
||||
// this will definitely not work if using remote daemon
|
||||
// very weird test
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
|
||||
dockerCmd(c, "load", "-i", "testdata/emptyLayer.tar")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSaveLoadParents(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
makeImage := func(from string, addfile string) string {
|
||||
var (
|
||||
out string
|
||||
)
|
||||
out, _ = dockerCmd(c, "run", "-d", from, "touch", addfile)
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "commit", cleanedContainerID)
|
||||
imageID := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "rm", "-f", cleanedContainerID)
|
||||
return imageID
|
||||
}
|
||||
|
||||
idFoo := makeImage("busybox", "foo")
|
||||
idBar := makeImage(idFoo, "bar")
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "save-load-parents")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
c.Log("tmpdir", tmpDir)
|
||||
|
||||
outfile := filepath.Join(tmpDir, "out.tar")
|
||||
|
||||
dockerCmd(c, "save", "-o", outfile, idBar, idFoo)
|
||||
dockerCmd(c, "rmi", idBar)
|
||||
dockerCmd(c, "load", "-i", outfile)
|
||||
|
||||
inspectOut := inspectField(c, idBar, "Parent")
|
||||
c.Assert(inspectOut, checker.Equals, idFoo)
|
||||
|
||||
inspectOut = inspectField(c, idFoo, "Parent")
|
||||
c.Assert(inspectOut, checker.Equals, "")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSaveLoadNoTag(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
name := "saveloadnotag"
|
||||
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENV foo=bar"))
|
||||
id := inspectField(c, name, "Id")
|
||||
|
||||
// Test to make sure that save w/o name just shows imageID during load
|
||||
out, err := RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "save", id),
|
||||
exec.Command(dockerBinary, "load"))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save and load repo: %s, %v", out, err))
|
||||
|
||||
// Should not show 'name' but should show the image ID during the load
|
||||
c.Assert(out, checker.Not(checker.Contains), "Loaded image: ")
|
||||
c.Assert(out, checker.Contains, "Loaded image ID:")
|
||||
c.Assert(out, checker.Contains, id)
|
||||
|
||||
// Test to make sure that save by name shows that name during load
|
||||
out, err = RunCommandPipelineWithOutput(
|
||||
exec.Command(dockerBinary, "save", name),
|
||||
exec.Command(dockerBinary, "load"))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to save and load repo: %s, %v", out, err))
|
||||
c.Assert(out, checker.Contains, "Loaded image: "+name+":latest")
|
||||
c.Assert(out, checker.Not(checker.Contains), "Loaded image ID:")
|
||||
}
|
107
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_save_load_unix_test.go
generated
vendored
Normal file
107
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_save_load_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
"github.com/kr/pty"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// save a repo and try to load it using stdout
|
||||
func (s *DockerSuite) TestSaveAndLoadRepoStdout(c *check.C) {
|
||||
name := "test-save-and-load-repo-stdout"
|
||||
dockerCmd(c, "run", "--name", name, "busybox", "true")
|
||||
|
||||
repoName := "foobar-save-load-test"
|
||||
before, _ := dockerCmd(c, "commit", name, repoName)
|
||||
before = strings.TrimRight(before, "\n")
|
||||
|
||||
tmpFile, err := ioutil.TempFile("", "foobar-save-load-test.tar")
|
||||
c.Assert(err, check.IsNil)
|
||||
defer os.Remove(tmpFile.Name())
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "save", repoName},
|
||||
Stdout: tmpFile,
|
||||
}).Assert(c, icmd.Success)
|
||||
|
||||
tmpFile, err = os.Open(tmpFile.Name())
|
||||
c.Assert(err, check.IsNil)
|
||||
defer tmpFile.Close()
|
||||
|
||||
deleteImages(repoName)
|
||||
|
||||
icmd.RunCmd(icmd.Cmd{
|
||||
Command: []string{dockerBinary, "load"},
|
||||
Stdin: tmpFile,
|
||||
}).Assert(c, icmd.Success)
|
||||
|
||||
after := inspectField(c, repoName, "Id")
|
||||
after = strings.TrimRight(after, "\n")
|
||||
|
||||
c.Assert(after, check.Equals, before) //inspect is not the same after a save / load
|
||||
|
||||
deleteImages(repoName)
|
||||
|
||||
pty, tty, err := pty.Open()
|
||||
c.Assert(err, check.IsNil)
|
||||
cmd := exec.Command(dockerBinary, "save", repoName)
|
||||
cmd.Stdin = tty
|
||||
cmd.Stdout = tty
|
||||
cmd.Stderr = tty
|
||||
c.Assert(cmd.Start(), check.IsNil)
|
||||
c.Assert(cmd.Wait(), check.NotNil) //did not break writing to a TTY
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
|
||||
n, err := pty.Read(buf)
|
||||
c.Assert(err, check.IsNil) //could not read tty output
|
||||
c.Assert(string(buf[:n]), checker.Contains, "cowardly refusing", check.Commentf("help output is not being yielded"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSaveAndLoadWithProgressBar(c *check.C) {
|
||||
name := "test-load"
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
|
||||
RUN touch aa
|
||||
`))
|
||||
|
||||
tmptar := name + ".tar"
|
||||
dockerCmd(c, "save", "-o", tmptar, name)
|
||||
defer os.Remove(tmptar)
|
||||
|
||||
dockerCmd(c, "rmi", name)
|
||||
dockerCmd(c, "tag", "busybox", name)
|
||||
out, _ := dockerCmd(c, "load", "-i", tmptar)
|
||||
expected := fmt.Sprintf("The image %s:latest already exists, renaming the old one with ID", name)
|
||||
c.Assert(out, checker.Contains, expected)
|
||||
}
|
||||
|
||||
// fail because load didn't receive data from stdin
|
||||
func (s *DockerSuite) TestLoadNoStdinFail(c *check.C) {
|
||||
pty, tty, err := pty.Open()
|
||||
c.Assert(err, check.IsNil)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, dockerBinary, "load")
|
||||
cmd.Stdin = tty
|
||||
cmd.Stdout = tty
|
||||
cmd.Stderr = tty
|
||||
c.Assert(cmd.Run(), check.NotNil) // docker-load should fail
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
|
||||
n, err := pty.Read(buf)
|
||||
c.Assert(err, check.IsNil) //could not read tty output
|
||||
c.Assert(string(buf[:n]), checker.Contains, "requested load from stdin, but stdin is empty")
|
||||
}
|
131
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_search_test.go
generated
vendored
Normal file
131
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_search_test.go
generated
vendored
Normal file
|
@ -0,0 +1,131 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// search for repos named "registry" on the central registry
|
||||
func (s *DockerSuite) TestSearchOnCentralRegistry(c *check.C) {
|
||||
testRequires(c, Network, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "search", "busybox")
|
||||
c.Assert(out, checker.Contains, "Busybox base image.", check.Commentf("couldn't find any repository named (or containing) 'Busybox base image.'"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSearchStarsOptionWithWrongParameter(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("search", "--filter", "stars=a", "busybox")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
|
||||
|
||||
out, _, err = dockerCmdWithError("search", "-f", "stars=a", "busybox")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
|
||||
|
||||
out, _, err = dockerCmdWithError("search", "-f", "is-automated=a", "busybox")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
|
||||
|
||||
out, _, err = dockerCmdWithError("search", "-f", "is-official=a", "busybox")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
|
||||
|
||||
// -s --stars deprecated since Docker 1.13
|
||||
out, _, err = dockerCmdWithError("search", "--stars=a", "busybox")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "invalid syntax", check.Commentf("couldn't find the invalid value warning"))
|
||||
|
||||
// -s --stars deprecated since Docker 1.13
|
||||
out, _, err = dockerCmdWithError("search", "-s=-1", "busybox")
|
||||
c.Assert(err, check.NotNil, check.Commentf("%s", out))
|
||||
c.Assert(out, checker.Contains, "invalid syntax", check.Commentf("couldn't find the invalid value warning"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestSearchCmdOptions(c *check.C) {
|
||||
testRequires(c, Network, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "search", "--help")
|
||||
c.Assert(out, checker.Contains, "Usage:\tdocker search [OPTIONS] TERM")
|
||||
|
||||
outSearchCmd, _ := dockerCmd(c, "search", "busybox")
|
||||
outSearchCmdNotrunc, _ := dockerCmd(c, "search", "--no-trunc=true", "busybox")
|
||||
|
||||
c.Assert(len(outSearchCmd) > len(outSearchCmdNotrunc), check.Equals, false, check.Commentf("The no-trunc option can't take effect."))
|
||||
|
||||
outSearchCmdautomated, _ := dockerCmd(c, "search", "--filter", "is-automated=true", "busybox") //The busybox is a busybox base image, not an AUTOMATED image.
|
||||
outSearchCmdautomatedSlice := strings.Split(outSearchCmdautomated, "\n")
|
||||
for i := range outSearchCmdautomatedSlice {
|
||||
c.Assert(strings.HasPrefix(outSearchCmdautomatedSlice[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an AUTOMATED image: %s", outSearchCmdautomated))
|
||||
}
|
||||
|
||||
outSearchCmdNotOfficial, _ := dockerCmd(c, "search", "--filter", "is-official=false", "busybox") //The busybox is a busybox base image, official image.
|
||||
outSearchCmdNotOfficialSlice := strings.Split(outSearchCmdNotOfficial, "\n")
|
||||
for i := range outSearchCmdNotOfficialSlice {
|
||||
c.Assert(strings.HasPrefix(outSearchCmdNotOfficialSlice[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an OFFICIAL image: %s", outSearchCmdNotOfficial))
|
||||
}
|
||||
|
||||
outSearchCmdOfficial, _ := dockerCmd(c, "search", "--filter", "is-official=true", "busybox") //The busybox is a busybox base image, official image.
|
||||
outSearchCmdOfficialSlice := strings.Split(outSearchCmdOfficial, "\n")
|
||||
c.Assert(outSearchCmdOfficialSlice, checker.HasLen, 3) // 1 header, 1 line, 1 carriage return
|
||||
c.Assert(strings.HasPrefix(outSearchCmdOfficialSlice[1], "busybox "), check.Equals, true, check.Commentf("The busybox is an OFFICIAL image: %s", outSearchCmdNotOfficial))
|
||||
|
||||
outSearchCmdStars, _ := dockerCmd(c, "search", "--filter", "stars=2", "busybox")
|
||||
c.Assert(strings.Count(outSearchCmdStars, "[OK]") > strings.Count(outSearchCmd, "[OK]"), check.Equals, false, check.Commentf("The quantity of images with stars should be less than that of all images: %s", outSearchCmdStars))
|
||||
|
||||
dockerCmd(c, "search", "--filter", "is-automated=true", "--filter", "stars=2", "--no-trunc=true", "busybox")
|
||||
|
||||
// --automated deprecated since Docker 1.13
|
||||
outSearchCmdautomated1, _ := dockerCmd(c, "search", "--automated=true", "busybox") //The busybox is a busybox base image, not an AUTOMATED image.
|
||||
outSearchCmdautomatedSlice1 := strings.Split(outSearchCmdautomated1, "\n")
|
||||
for i := range outSearchCmdautomatedSlice1 {
|
||||
c.Assert(strings.HasPrefix(outSearchCmdautomatedSlice1[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an AUTOMATED image: %s", outSearchCmdautomated))
|
||||
}
|
||||
|
||||
// -s --stars deprecated since Docker 1.13
|
||||
outSearchCmdStars1, _ := dockerCmd(c, "search", "--stars=2", "busybox")
|
||||
c.Assert(strings.Count(outSearchCmdStars1, "[OK]") > strings.Count(outSearchCmd, "[OK]"), check.Equals, false, check.Commentf("The quantity of images with stars should be less than that of all images: %s", outSearchCmdStars1))
|
||||
|
||||
// -s --stars deprecated since Docker 1.13
|
||||
dockerCmd(c, "search", "--stars=2", "--automated=true", "--no-trunc=true", "busybox")
|
||||
}
|
||||
|
||||
// search for repos which start with "ubuntu-" on the central registry
|
||||
func (s *DockerSuite) TestSearchOnCentralRegistryWithDash(c *check.C) {
|
||||
testRequires(c, Network, DaemonIsLinux)
|
||||
|
||||
dockerCmd(c, "search", "ubuntu-")
|
||||
}
|
||||
|
||||
// test case for #23055
|
||||
func (s *DockerSuite) TestSearchWithLimit(c *check.C) {
|
||||
testRequires(c, Network, DaemonIsLinux)
|
||||
|
||||
limit := 10
|
||||
out, _, err := dockerCmdWithError("search", fmt.Sprintf("--limit=%d", limit), "docker")
|
||||
c.Assert(err, checker.IsNil)
|
||||
outSlice := strings.Split(out, "\n")
|
||||
c.Assert(outSlice, checker.HasLen, limit+2) // 1 header, 1 carriage return
|
||||
|
||||
limit = 50
|
||||
out, _, err = dockerCmdWithError("search", fmt.Sprintf("--limit=%d", limit), "docker")
|
||||
c.Assert(err, checker.IsNil)
|
||||
outSlice = strings.Split(out, "\n")
|
||||
c.Assert(outSlice, checker.HasLen, limit+2) // 1 header, 1 carriage return
|
||||
|
||||
limit = 100
|
||||
out, _, err = dockerCmdWithError("search", fmt.Sprintf("--limit=%d", limit), "docker")
|
||||
c.Assert(err, checker.IsNil)
|
||||
outSlice = strings.Split(out, "\n")
|
||||
c.Assert(outSlice, checker.HasLen, limit+2) // 1 header, 1 carriage return
|
||||
|
||||
limit = 0
|
||||
_, _, err = dockerCmdWithError("search", fmt.Sprintf("--limit=%d", limit), "docker")
|
||||
c.Assert(err, checker.Not(checker.IsNil))
|
||||
|
||||
limit = 200
|
||||
_, _, err = dockerCmdWithError("search", fmt.Sprintf("--limit=%d", limit), "docker")
|
||||
c.Assert(err, checker.Not(checker.IsNil))
|
||||
}
|
95
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_secret_create_test.go
generated
vendored
Normal file
95
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_secret_create_test.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// Test case for 28884
|
||||
func (s *DockerSwarmSuite) TestSecretCreateResolve(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
name := "test_secret"
|
||||
id := d.CreateSecret(c, swarm.SecretSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: name,
|
||||
},
|
||||
Data: []byte("foo"),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
|
||||
|
||||
fake := d.CreateSecret(c, swarm.SecretSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: id,
|
||||
},
|
||||
Data: []byte("fake foo"),
|
||||
})
|
||||
c.Assert(fake, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", fake))
|
||||
|
||||
out, err := d.Cmd("secret", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, name)
|
||||
c.Assert(out, checker.Contains, fake)
|
||||
|
||||
out, err = d.Cmd("secret", "rm", id)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, id)
|
||||
|
||||
// Fake one will remain
|
||||
out, err = d.Cmd("secret", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Not(checker.Contains), name)
|
||||
c.Assert(out, checker.Contains, fake)
|
||||
|
||||
// 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)
|
||||
out, err = d.Cmd("secret", "rm", id[:5])
|
||||
c.Assert(err, checker.Not(checker.IsNil))
|
||||
c.Assert(out, checker.Not(checker.Contains), id)
|
||||
out, err = d.Cmd("secret", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Not(checker.Contains), name)
|
||||
c.Assert(out, checker.Contains, fake)
|
||||
|
||||
// Remove based on ID prefix of the fake one should succeed
|
||||
out, err = d.Cmd("secret", "rm", fake[:5])
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Contains, fake[:5])
|
||||
out, err = d.Cmd("secret", "ls")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Not(checker.Contains), name)
|
||||
c.Assert(out, checker.Not(checker.Contains), id)
|
||||
c.Assert(out, checker.Not(checker.Contains), fake)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestSecretCreateWithFile(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
testFile, err := ioutil.TempFile("", "secretCreateTest")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to create temporary file"))
|
||||
defer os.Remove(testFile.Name())
|
||||
|
||||
testData := "TESTINGDATA"
|
||||
_, err = testFile.Write([]byte(testData))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to write to temporary file"))
|
||||
|
||||
testName := "test_secret"
|
||||
out, err := d.Cmd("secret", "create", testName, testFile.Name())
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "", check.Commentf("%s", out))
|
||||
|
||||
id := strings.TrimSpace(out)
|
||||
secret := d.GetSecret(c, id)
|
||||
c.Assert(secret.Spec.Name, checker.Equals, testName)
|
||||
}
|
447
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_service_create_test.go
generated
vendored
Normal file
447
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_service_create_test.go
generated
vendored
Normal file
|
@ -0,0 +1,447 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceCreateMountVolume(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--mount", "type=volume,source=foo,target=/foo,volume-nocopy", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
var tasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks = d.GetServiceTasks(c, id)
|
||||
return len(tasks) > 0, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
task := tasks[0]
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
if task.NodeID == "" || task.Status.ContainerStatus == nil {
|
||||
task = d.GetTask(c, task.ID)
|
||||
}
|
||||
return task.NodeID != "" && task.Status.ContainerStatus != nil, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
// check container mount config
|
||||
out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .HostConfig.Mounts}}", task.Status.ContainerStatus.ContainerID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
var mountConfig []mount.Mount
|
||||
c.Assert(json.Unmarshal([]byte(out), &mountConfig), checker.IsNil)
|
||||
c.Assert(mountConfig, checker.HasLen, 1)
|
||||
|
||||
c.Assert(mountConfig[0].Source, checker.Equals, "foo")
|
||||
c.Assert(mountConfig[0].Target, checker.Equals, "/foo")
|
||||
c.Assert(mountConfig[0].Type, checker.Equals, mount.TypeVolume)
|
||||
c.Assert(mountConfig[0].VolumeOptions, checker.NotNil)
|
||||
c.Assert(mountConfig[0].VolumeOptions.NoCopy, checker.True)
|
||||
|
||||
// check container mounts actual
|
||||
out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .Mounts}}", task.Status.ContainerStatus.ContainerID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
var mounts []types.MountPoint
|
||||
c.Assert(json.Unmarshal([]byte(out), &mounts), checker.IsNil)
|
||||
c.Assert(mounts, checker.HasLen, 1)
|
||||
|
||||
c.Assert(mounts[0].Type, checker.Equals, mount.TypeVolume)
|
||||
c.Assert(mounts[0].Name, checker.Equals, "foo")
|
||||
c.Assert(mounts[0].Destination, checker.Equals, "/foo")
|
||||
c.Assert(mounts[0].RW, checker.Equals, true)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceCreateWithSecretSimple(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
serviceName := "test-service-secret"
|
||||
testName := "test_secret"
|
||||
id := d.CreateSecret(c, swarm.SecretSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: testName,
|
||||
},
|
||||
Data: []byte("TESTINGDATA"),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
|
||||
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "--secret", testName, "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Secrets }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var refs []swarm.SecretReference
|
||||
c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
|
||||
c.Assert(refs, checker.HasLen, 1)
|
||||
|
||||
c.Assert(refs[0].SecretName, checker.Equals, testName)
|
||||
c.Assert(refs[0].File, checker.Not(checker.IsNil))
|
||||
c.Assert(refs[0].File.Name, checker.Equals, testName)
|
||||
c.Assert(refs[0].File.UID, checker.Equals, "0")
|
||||
c.Assert(refs[0].File.GID, checker.Equals, "0")
|
||||
|
||||
out, err = d.Cmd("service", "rm", serviceName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
d.DeleteSecret(c, testName)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceCreateWithSecretSourceTargetPaths(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
testPaths := map[string]string{
|
||||
"app": "/etc/secret",
|
||||
"test_secret": "test_secret",
|
||||
"relative_secret": "relative/secret",
|
||||
"escapes_in_container": "../secret",
|
||||
}
|
||||
|
||||
var secretFlags []string
|
||||
|
||||
for testName, testTarget := range testPaths {
|
||||
id := d.CreateSecret(c, swarm.SecretSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: testName,
|
||||
},
|
||||
Data: []byte("TESTINGDATA " + testName + " " + testTarget),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
|
||||
|
||||
secretFlags = append(secretFlags, "--secret", fmt.Sprintf("source=%s,target=%s", testName, testTarget))
|
||||
}
|
||||
|
||||
serviceName := "svc"
|
||||
serviceCmd := []string{"service", "create", "--detach", "--no-resolve-image", "--name", serviceName}
|
||||
serviceCmd = append(serviceCmd, secretFlags...)
|
||||
serviceCmd = append(serviceCmd, "busybox", "top")
|
||||
out, err := d.Cmd(serviceCmd...)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Secrets }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var refs []swarm.SecretReference
|
||||
c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
|
||||
c.Assert(refs, checker.HasLen, len(testPaths))
|
||||
|
||||
var tasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks = d.GetServiceTasks(c, serviceName)
|
||||
return len(tasks) > 0, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
task := tasks[0]
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
if task.NodeID == "" || task.Status.ContainerStatus == nil {
|
||||
task = d.GetTask(c, task.ID)
|
||||
}
|
||||
return task.NodeID != "" && task.Status.ContainerStatus != nil, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
for testName, testTarget := range testPaths {
|
||||
path := testTarget
|
||||
if !filepath.IsAbs(path) {
|
||||
path = filepath.Join("/run/secrets", path)
|
||||
}
|
||||
out, err := d.Cmd("exec", task.Status.ContainerStatus.ContainerID, "cat", path)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Equals, "TESTINGDATA "+testName+" "+testTarget)
|
||||
}
|
||||
|
||||
out, err = d.Cmd("service", "rm", serviceName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceCreateWithSecretReferencedTwice(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
id := d.CreateSecret(c, swarm.SecretSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: "mysecret",
|
||||
},
|
||||
Data: []byte("TESTINGDATA"),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
|
||||
|
||||
serviceName := "svc"
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "--secret", "source=mysecret,target=target1", "--secret", "source=mysecret,target=target2", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Secrets }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var refs []swarm.SecretReference
|
||||
c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
|
||||
c.Assert(refs, checker.HasLen, 2)
|
||||
|
||||
var tasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks = d.GetServiceTasks(c, serviceName)
|
||||
return len(tasks) > 0, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
task := tasks[0]
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
if task.NodeID == "" || task.Status.ContainerStatus == nil {
|
||||
task = d.GetTask(c, task.ID)
|
||||
}
|
||||
return task.NodeID != "" && task.Status.ContainerStatus != nil, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
for _, target := range []string{"target1", "target2"} {
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
path := filepath.Join("/run/secrets", target)
|
||||
out, err := d.Cmd("exec", task.Status.ContainerStatus.ContainerID, "cat", path)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Equals, "TESTINGDATA")
|
||||
}
|
||||
|
||||
out, err = d.Cmd("service", "rm", serviceName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceCreateWithConfigSimple(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
serviceName := "test-service-config"
|
||||
testName := "test_config"
|
||||
id := d.CreateConfig(c, swarm.ConfigSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: testName,
|
||||
},
|
||||
Data: []byte("TESTINGDATA"),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
|
||||
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "--config", testName, "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Configs }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var refs []swarm.ConfigReference
|
||||
c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
|
||||
c.Assert(refs, checker.HasLen, 1)
|
||||
|
||||
c.Assert(refs[0].ConfigName, checker.Equals, testName)
|
||||
c.Assert(refs[0].File, checker.Not(checker.IsNil))
|
||||
c.Assert(refs[0].File.Name, checker.Equals, testName)
|
||||
c.Assert(refs[0].File.UID, checker.Equals, "0")
|
||||
c.Assert(refs[0].File.GID, checker.Equals, "0")
|
||||
|
||||
out, err = d.Cmd("service", "rm", serviceName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
d.DeleteConfig(c, testName)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceCreateWithConfigSourceTargetPaths(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
testPaths := map[string]string{
|
||||
"app": "/etc/config",
|
||||
"test_config": "test_config",
|
||||
"relative_config": "relative/config",
|
||||
}
|
||||
|
||||
var configFlags []string
|
||||
|
||||
for testName, testTarget := range testPaths {
|
||||
id := d.CreateConfig(c, swarm.ConfigSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: testName,
|
||||
},
|
||||
Data: []byte("TESTINGDATA " + testName + " " + testTarget),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
|
||||
|
||||
configFlags = append(configFlags, "--config", fmt.Sprintf("source=%s,target=%s", testName, testTarget))
|
||||
}
|
||||
|
||||
serviceName := "svc"
|
||||
serviceCmd := []string{"service", "create", "--detach", "--no-resolve-image", "--name", serviceName}
|
||||
serviceCmd = append(serviceCmd, configFlags...)
|
||||
serviceCmd = append(serviceCmd, "busybox", "top")
|
||||
out, err := d.Cmd(serviceCmd...)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Configs }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var refs []swarm.ConfigReference
|
||||
c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
|
||||
c.Assert(refs, checker.HasLen, len(testPaths))
|
||||
|
||||
var tasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks = d.GetServiceTasks(c, serviceName)
|
||||
return len(tasks) > 0, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
task := tasks[0]
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
if task.NodeID == "" || task.Status.ContainerStatus == nil {
|
||||
task = d.GetTask(c, task.ID)
|
||||
}
|
||||
return task.NodeID != "" && task.Status.ContainerStatus != nil, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
for testName, testTarget := range testPaths {
|
||||
path := testTarget
|
||||
if !filepath.IsAbs(path) {
|
||||
path = filepath.Join("/", path)
|
||||
}
|
||||
out, err := d.Cmd("exec", task.Status.ContainerStatus.ContainerID, "cat", path)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Equals, "TESTINGDATA "+testName+" "+testTarget)
|
||||
}
|
||||
|
||||
out, err = d.Cmd("service", "rm", serviceName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceCreateWithConfigReferencedTwice(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
id := d.CreateConfig(c, swarm.ConfigSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: "myconfig",
|
||||
},
|
||||
Data: []byte("TESTINGDATA"),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
|
||||
|
||||
serviceName := "svc"
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "--config", "source=myconfig,target=target1", "--config", "source=myconfig,target=target2", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Configs }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var refs []swarm.ConfigReference
|
||||
c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
|
||||
c.Assert(refs, checker.HasLen, 2)
|
||||
|
||||
var tasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks = d.GetServiceTasks(c, serviceName)
|
||||
return len(tasks) > 0, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
task := tasks[0]
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
if task.NodeID == "" || task.Status.ContainerStatus == nil {
|
||||
task = d.GetTask(c, task.ID)
|
||||
}
|
||||
return task.NodeID != "" && task.Status.ContainerStatus != nil, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
for _, target := range []string{"target1", "target2"} {
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
path := filepath.Join("/", target)
|
||||
out, err := d.Cmd("exec", task.Status.ContainerStatus.ContainerID, "cat", path)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(out, checker.Equals, "TESTINGDATA")
|
||||
}
|
||||
|
||||
out, err = d.Cmd("service", "rm", serviceName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceCreateMountTmpfs(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--mount", "type=tmpfs,target=/foo,tmpfs-size=1MB", "busybox", "sh", "-c", "mount | grep foo; tail -f /dev/null")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
var tasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks = d.GetServiceTasks(c, id)
|
||||
return len(tasks) > 0, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
task := tasks[0]
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
if task.NodeID == "" || task.Status.ContainerStatus == nil {
|
||||
task = d.GetTask(c, task.ID)
|
||||
}
|
||||
return task.NodeID != "" && task.Status.ContainerStatus != nil, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
// check container mount config
|
||||
out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .HostConfig.Mounts}}", task.Status.ContainerStatus.ContainerID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
var mountConfig []mount.Mount
|
||||
c.Assert(json.Unmarshal([]byte(out), &mountConfig), checker.IsNil)
|
||||
c.Assert(mountConfig, checker.HasLen, 1)
|
||||
|
||||
c.Assert(mountConfig[0].Source, checker.Equals, "")
|
||||
c.Assert(mountConfig[0].Target, checker.Equals, "/foo")
|
||||
c.Assert(mountConfig[0].Type, checker.Equals, mount.TypeTmpfs)
|
||||
c.Assert(mountConfig[0].TmpfsOptions, checker.NotNil)
|
||||
c.Assert(mountConfig[0].TmpfsOptions.SizeBytes, checker.Equals, int64(1048576))
|
||||
|
||||
// check container mounts actual
|
||||
out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .Mounts}}", task.Status.ContainerStatus.ContainerID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
var mounts []types.MountPoint
|
||||
c.Assert(json.Unmarshal([]byte(out), &mounts), checker.IsNil)
|
||||
c.Assert(mounts, checker.HasLen, 1)
|
||||
|
||||
c.Assert(mounts[0].Type, checker.Equals, mount.TypeTmpfs)
|
||||
c.Assert(mounts[0].Name, checker.Equals, "")
|
||||
c.Assert(mounts[0].Destination, checker.Equals, "/foo")
|
||||
c.Assert(mounts[0].RW, checker.Equals, true)
|
||||
|
||||
out, err = s.nodeCmd(c, task.NodeID, "logs", task.Status.ContainerStatus.ContainerID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
c.Assert(strings.TrimSpace(out), checker.HasPrefix, "tmpfs on /foo type tmpfs")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "size=1024k")
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceCreateWithNetworkAlias(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
out, err := d.Cmd("network", "create", "--scope=swarm", "test_swarm_br")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--network=name=test_swarm_br,alias=srv_alias", "--name=alias_tst_container", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
var tasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks = d.GetServiceTasks(c, id)
|
||||
return len(tasks) > 0, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
task := tasks[0]
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
if task.NodeID == "" || task.Status.ContainerStatus == nil {
|
||||
task = d.GetTask(c, task.ID)
|
||||
}
|
||||
return task.NodeID != "" && task.Status.ContainerStatus != nil, nil
|
||||
}, checker.Equals, true)
|
||||
|
||||
// check container alias config
|
||||
out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .NetworkSettings.Networks.test_swarm_br.Aliases}}", task.Status.ContainerStatus.ContainerID)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
// Make sure the only alias seen is the container-id
|
||||
var aliases []string
|
||||
c.Assert(json.Unmarshal([]byte(out), &aliases), checker.IsNil)
|
||||
c.Assert(aliases, checker.HasLen, 1)
|
||||
|
||||
c.Assert(task.Status.ContainerStatus.ContainerID, checker.Contains, aliases[0])
|
||||
}
|
136
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_service_health_test.go
generated
vendored
Normal file
136
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_service_health_test.go
generated
vendored
Normal file
|
@ -0,0 +1,136 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/daemon/cluster/executor/container"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// start a service, and then make its task unhealthy during running
|
||||
// finally, unhealthy task should be detected and killed
|
||||
func (s *DockerSwarmSuite) TestServiceHealthRun(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows
|
||||
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
// build image with health-check
|
||||
imageName := "testhealth"
|
||||
result := cli.BuildCmd(c, imageName, cli.Daemon(d),
|
||||
build.WithDockerfile(`FROM busybox
|
||||
RUN touch /status
|
||||
HEALTHCHECK --interval=1s --timeout=1s --retries=1\
|
||||
CMD cat /status`),
|
||||
)
|
||||
result.Assert(c, icmd.Success)
|
||||
|
||||
serviceName := "healthServiceRun"
|
||||
out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--name", serviceName, imageName, "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
var tasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks = d.GetServiceTasks(c, id)
|
||||
return tasks, nil
|
||||
}, checker.HasLen, 1)
|
||||
|
||||
task := tasks[0]
|
||||
|
||||
// wait for task to start
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
task = d.GetTask(c, task.ID)
|
||||
return task.Status.State, nil
|
||||
}, checker.Equals, swarm.TaskStateRunning)
|
||||
containerID := task.Status.ContainerStatus.ContainerID
|
||||
|
||||
// wait for container to be healthy
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
out, _ := d.Cmd("inspect", "--format={{.State.Health.Status}}", containerID)
|
||||
return strings.TrimSpace(out), nil
|
||||
}, checker.Equals, "healthy")
|
||||
|
||||
// make it fail
|
||||
d.Cmd("exec", containerID, "rm", "/status")
|
||||
// wait for container to be unhealthy
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
out, _ := d.Cmd("inspect", "--format={{.State.Health.Status}}", containerID)
|
||||
return strings.TrimSpace(out), nil
|
||||
}, checker.Equals, "unhealthy")
|
||||
|
||||
// Task should be terminated
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
task = d.GetTask(c, task.ID)
|
||||
return task.Status.State, nil
|
||||
}, checker.Equals, swarm.TaskStateFailed)
|
||||
|
||||
if !strings.Contains(task.Status.Err, container.ErrContainerUnhealthy.Error()) {
|
||||
c.Fatal("unhealthy task exits because of other error")
|
||||
}
|
||||
}
|
||||
|
||||
// start a service whose task is unhealthy at beginning
|
||||
// its tasks should be blocked in starting stage, until health check is passed
|
||||
func (s *DockerSwarmSuite) TestServiceHealthStart(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows
|
||||
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
// service started from this image won't pass health check
|
||||
imageName := "testhealth"
|
||||
result := cli.BuildCmd(c, imageName, cli.Daemon(d),
|
||||
build.WithDockerfile(`FROM busybox
|
||||
HEALTHCHECK --interval=1s --timeout=1s --retries=1024\
|
||||
CMD cat /status`),
|
||||
)
|
||||
result.Assert(c, icmd.Success)
|
||||
|
||||
serviceName := "healthServiceStart"
|
||||
out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--name", serviceName, imageName, "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
var tasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks = d.GetServiceTasks(c, id)
|
||||
return tasks, nil
|
||||
}, checker.HasLen, 1)
|
||||
|
||||
task := tasks[0]
|
||||
|
||||
// wait for task to start
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
task = d.GetTask(c, task.ID)
|
||||
return task.Status.State, nil
|
||||
}, checker.Equals, swarm.TaskStateStarting)
|
||||
|
||||
containerID := task.Status.ContainerStatus.ContainerID
|
||||
|
||||
// wait for health check to work
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
out, _ := d.Cmd("inspect", "--format={{.State.Health.FailingStreak}}", containerID)
|
||||
failingStreak, _ := strconv.Atoi(strings.TrimSpace(out))
|
||||
return failingStreak, nil
|
||||
}, checker.GreaterThan, 0)
|
||||
|
||||
// task should be blocked at starting status
|
||||
task = d.GetTask(c, task.ID)
|
||||
c.Assert(task.Status.State, check.Equals, swarm.TaskStateStarting)
|
||||
|
||||
// make it healthy
|
||||
d.Cmd("exec", containerID, "touch", "/status")
|
||||
|
||||
// Task should be at running status
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
task = d.GetTask(c, task.ID)
|
||||
return task.Status.State, nil
|
||||
}, checker.Equals, swarm.TaskStateRunning)
|
||||
}
|
388
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_service_logs_test.go
generated
vendored
Normal file
388
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_service_logs_test.go
generated
vendored
Normal file
|
@ -0,0 +1,388 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
type logMessage struct {
|
||||
err error
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceLogs(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
// we have multiple services here for detecting the goroutine issue #28915
|
||||
services := map[string]string{
|
||||
"TestServiceLogs1": "hello1",
|
||||
"TestServiceLogs2": "hello2",
|
||||
}
|
||||
|
||||
for name, message := range services {
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox",
|
||||
"sh", "-c", fmt.Sprintf("echo %s; tail -f /dev/null", message))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
}
|
||||
|
||||
// make sure task has been deployed.
|
||||
waitAndAssert(c, defaultReconciliationTimeout,
|
||||
d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{"busybox:latest": len(services)})
|
||||
|
||||
for name, message := range services {
|
||||
out, err := d.Cmd("service", "logs", name)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Logf("log for %q: %q", name, out)
|
||||
c.Assert(out, checker.Contains, message)
|
||||
}
|
||||
}
|
||||
|
||||
// countLogLines returns a closure that can be used with waitAndAssert to
|
||||
// verify that a minimum number of expected container log messages have been
|
||||
// output.
|
||||
func countLogLines(d *daemon.Daemon, name string) func(*check.C) (interface{}, check.CommentInterface) {
|
||||
return func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
result := icmd.RunCmd(d.Command("service", "logs", "-t", "--raw", name))
|
||||
result.Assert(c, icmd.Expected{})
|
||||
// if this returns an emptystring, trying to split it later will return
|
||||
// an array containing emptystring. a valid log line will NEVER be
|
||||
// emptystring because we ask for the timestamp.
|
||||
if result.Stdout() == "" {
|
||||
return 0, check.Commentf("Empty stdout")
|
||||
}
|
||||
lines := strings.Split(strings.TrimSpace(result.Stdout()), "\n")
|
||||
return len(lines), check.Commentf("output, %q", string(result.Stdout()))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceLogsCompleteness(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
name := "TestServiceLogsCompleteness"
|
||||
|
||||
// make a service that prints 6 lines
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "sh", "-c", "for line in $(seq 0 5); do echo log test $line; done; sleep 100000")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
|
||||
// make sure task has been deployed.
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
|
||||
// and make sure we have all the log lines
|
||||
waitAndAssert(c, defaultReconciliationTimeout, countLogLines(d, name), checker.Equals, 6)
|
||||
|
||||
out, err = d.Cmd("service", "logs", name)
|
||||
c.Assert(err, checker.IsNil)
|
||||
lines := strings.Split(strings.TrimSpace(out), "\n")
|
||||
|
||||
// i have heard anecdotal reports that logs may come back from the engine
|
||||
// mis-ordered. if this tests fails, consider the possibility that that
|
||||
// might be occurring
|
||||
for i, line := range lines {
|
||||
c.Assert(line, checker.Contains, fmt.Sprintf("log test %v", i))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceLogsTail(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
name := "TestServiceLogsTail"
|
||||
|
||||
// make a service that prints 6 lines
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "sh", "-c", "for line in $(seq 1 6); do echo log test $line; done; sleep 100000")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
|
||||
// make sure task has been deployed.
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, countLogLines(d, name), checker.Equals, 6)
|
||||
|
||||
out, err = d.Cmd("service", "logs", "--tail=2", name)
|
||||
c.Assert(err, checker.IsNil)
|
||||
lines := strings.Split(strings.TrimSpace(out), "\n")
|
||||
|
||||
for i, line := range lines {
|
||||
// doing i+5 is hacky but not too fragile, it's good enough. if it flakes something else is wrong
|
||||
c.Assert(line, checker.Contains, fmt.Sprintf("log test %v", i+5))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceLogsSince(c *check.C) {
|
||||
// See DockerSuite.TestLogsSince, which is where this comes from
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
name := "TestServiceLogsSince"
|
||||
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "sh", "-c", "for i in $(seq 1 3); do sleep .1; echo log$i; done; sleep 10000000")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
|
||||
// wait a sec for the logs to come in
|
||||
waitAndAssert(c, defaultReconciliationTimeout, countLogLines(d, name), checker.Equals, 3)
|
||||
|
||||
out, err = d.Cmd("service", "logs", "-t", name)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
log2Line := strings.Split(strings.Split(out, "\n")[1], " ")
|
||||
t, err := time.Parse(time.RFC3339Nano, log2Line[0]) // timestamp log2 is written
|
||||
c.Assert(err, checker.IsNil)
|
||||
u := t.Add(50 * time.Millisecond) // add .05s so log1 & log2 don't show up
|
||||
since := u.Format(time.RFC3339Nano)
|
||||
|
||||
out, err = d.Cmd("service", "logs", "-t", fmt.Sprintf("--since=%v", since), name)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
unexpected := []string{"log1", "log2"}
|
||||
expected := []string{"log3"}
|
||||
for _, v := range unexpected {
|
||||
c.Assert(out, checker.Not(checker.Contains), v, check.Commentf("unexpected log message returned, since=%v", u))
|
||||
}
|
||||
for _, v := range expected {
|
||||
c.Assert(out, checker.Contains, v, check.Commentf("expected log message %v, was not present, since=%v", u))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceLogsFollow(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
name := "TestServiceLogsFollow"
|
||||
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "sh", "-c", "while true; do echo log test; sleep 0.1; done")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
|
||||
// make sure task has been deployed.
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
|
||||
|
||||
args := []string{"service", "logs", "-f", name}
|
||||
cmd := exec.Command(dockerBinary, d.PrependHostArg(args)...)
|
||||
r, w := io.Pipe()
|
||||
cmd.Stdout = w
|
||||
cmd.Stderr = w
|
||||
c.Assert(cmd.Start(), checker.IsNil)
|
||||
go cmd.Wait()
|
||||
|
||||
// Make sure pipe is written to
|
||||
ch := make(chan *logMessage)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
reader := bufio.NewReader(r)
|
||||
for {
|
||||
msg := &logMessage{}
|
||||
msg.data, _, msg.err = reader.ReadLine()
|
||||
select {
|
||||
case ch <- msg:
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
msg := <-ch
|
||||
c.Assert(msg.err, checker.IsNil)
|
||||
c.Assert(string(msg.data), checker.Contains, "log test")
|
||||
}
|
||||
close(done)
|
||||
|
||||
c.Assert(cmd.Process.Kill(), checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceLogsTaskLogs(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
name := "TestServicelogsTaskLogs"
|
||||
replicas := 2
|
||||
|
||||
result := icmd.RunCmd(d.Command(
|
||||
// create a service with the name
|
||||
"service", "create", "--detach", "--no-resolve-image", "--name", name,
|
||||
// which has some number of replicas
|
||||
fmt.Sprintf("--replicas=%v", replicas),
|
||||
// which has this the task id as an environment variable templated in
|
||||
"--env", "TASK={{.Task.ID}}",
|
||||
// and runs this command to print exactly 6 logs lines
|
||||
"busybox", "sh", "-c", "for line in $(seq 0 5); do echo $TASK log test $line; done; sleep 100000",
|
||||
))
|
||||
result.Assert(c, icmd.Expected{})
|
||||
// ^^ verify that we get no error
|
||||
// then verify that we have an id in stdout
|
||||
id := strings.TrimSpace(result.Stdout())
|
||||
c.Assert(id, checker.Not(checker.Equals), "")
|
||||
// so, right here, we're basically inspecting by id and returning only
|
||||
// the ID. if they don't match, the service doesn't exist.
|
||||
result = icmd.RunCmd(d.Command("service", "inspect", "--format=\"{{.ID}}\"", id))
|
||||
result.Assert(c, icmd.Expected{Out: id})
|
||||
|
||||
// make sure task has been deployed.
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, replicas)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, countLogLines(d, name), checker.Equals, 6*replicas)
|
||||
|
||||
// get the task ids
|
||||
result = icmd.RunCmd(d.Command("service", "ps", "-q", name))
|
||||
result.Assert(c, icmd.Expected{})
|
||||
// make sure we have two tasks
|
||||
taskIDs := strings.Split(strings.TrimSpace(result.Stdout()), "\n")
|
||||
c.Assert(taskIDs, checker.HasLen, replicas)
|
||||
|
||||
for _, taskID := range taskIDs {
|
||||
c.Logf("checking task %v", taskID)
|
||||
result := icmd.RunCmd(d.Command("service", "logs", taskID))
|
||||
result.Assert(c, icmd.Expected{})
|
||||
lines := strings.Split(strings.TrimSpace(result.Stdout()), "\n")
|
||||
|
||||
c.Logf("checking messages for %v", taskID)
|
||||
for i, line := range lines {
|
||||
// make sure the message is in order
|
||||
c.Assert(line, checker.Contains, fmt.Sprintf("log test %v", i))
|
||||
// make sure it contains the task id
|
||||
c.Assert(line, checker.Contains, taskID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceLogsTTY(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
name := "TestServiceLogsTTY"
|
||||
|
||||
result := icmd.RunCmd(d.Command(
|
||||
// create a service
|
||||
"service", "create", "--detach", "--no-resolve-image",
|
||||
// name it $name
|
||||
"--name", name,
|
||||
// use a TTY
|
||||
"-t",
|
||||
// busybox image, shell string
|
||||
"busybox", "sh", "-c",
|
||||
// echo to stdout and stderr
|
||||
"echo out; (echo err 1>&2); sleep 10000",
|
||||
))
|
||||
|
||||
result.Assert(c, icmd.Expected{})
|
||||
id := strings.TrimSpace(result.Stdout())
|
||||
c.Assert(id, checker.Not(checker.Equals), "")
|
||||
// so, right here, we're basically inspecting by id and returning only
|
||||
// the ID. if they don't match, the service doesn't exist.
|
||||
result = icmd.RunCmd(d.Command("service", "inspect", "--format=\"{{.ID}}\"", id))
|
||||
result.Assert(c, icmd.Expected{Out: id})
|
||||
|
||||
// make sure task has been deployed.
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
|
||||
// and make sure we have all the log lines
|
||||
waitAndAssert(c, defaultReconciliationTimeout, countLogLines(d, name), checker.Equals, 2)
|
||||
|
||||
cmd := d.Command("service", "logs", "--raw", name)
|
||||
result = icmd.RunCmd(cmd)
|
||||
// for some reason there is carriage return in the output. i think this is
|
||||
// just expected.
|
||||
result.Assert(c, icmd.Expected{Out: "out\r\nerr\r\n"})
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceLogsNoHangDeletedContainer(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
name := "TestServiceLogsNoHangDeletedContainer"
|
||||
|
||||
result := icmd.RunCmd(d.Command(
|
||||
// create a service
|
||||
"service", "create", "--detach", "--no-resolve-image",
|
||||
// name it $name
|
||||
"--name", name,
|
||||
// busybox image, shell string
|
||||
"busybox", "sh", "-c",
|
||||
// echo to stdout and stderr
|
||||
"while true; do echo line; sleep 2; done",
|
||||
))
|
||||
|
||||
// confirm that the command succeeded
|
||||
result.Assert(c, icmd.Expected{})
|
||||
// get the service id
|
||||
id := strings.TrimSpace(result.Stdout())
|
||||
c.Assert(id, checker.Not(checker.Equals), "")
|
||||
|
||||
// make sure task has been deployed.
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
|
||||
// and make sure we have all the log lines
|
||||
waitAndAssert(c, defaultReconciliationTimeout, countLogLines(d, name), checker.Equals, 2)
|
||||
|
||||
// now find and nuke the container
|
||||
result = icmd.RunCmd(d.Command("ps", "-q"))
|
||||
containerID := strings.TrimSpace(result.Stdout())
|
||||
c.Assert(containerID, checker.Not(checker.Equals), "")
|
||||
result = icmd.RunCmd(d.Command("stop", containerID))
|
||||
result.Assert(c, icmd.Expected{Out: containerID})
|
||||
result = icmd.RunCmd(d.Command("rm", containerID))
|
||||
result.Assert(c, icmd.Expected{Out: containerID})
|
||||
|
||||
// run logs. use tail 2 to make sure we don't try to get a bunch of logs
|
||||
// somehow and slow down execution time
|
||||
cmd := d.Command("service", "logs", "--tail", "2", id)
|
||||
// start the command and then wait for it to finish with a 3 second timeout
|
||||
result = icmd.StartCmd(cmd)
|
||||
result = icmd.WaitOnCmd(3*time.Second, result)
|
||||
|
||||
// then, assert that the result matches expected. if the command timed out,
|
||||
// if the command is timed out, result.Timeout will be true, but the
|
||||
// Expected defaults to false
|
||||
result.Assert(c, icmd.Expected{})
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceLogsDetails(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
name := "TestServiceLogsDetails"
|
||||
|
||||
result := icmd.RunCmd(d.Command(
|
||||
// create a service
|
||||
"service", "create", "--detach", "--no-resolve-image",
|
||||
// name it $name
|
||||
"--name", name,
|
||||
// add an environment variable
|
||||
"--env", "asdf=test1",
|
||||
// add a log driver (without explicitly setting a driver, log-opt doesn't work)
|
||||
"--log-driver", "json-file",
|
||||
// add a log option to print the environment variable
|
||||
"--log-opt", "env=asdf",
|
||||
// busybox image, shell string
|
||||
"busybox", "sh", "-c",
|
||||
// make a log line
|
||||
"echo LogLine; while true; do sleep 1; done;",
|
||||
))
|
||||
|
||||
result.Assert(c, icmd.Expected{})
|
||||
id := strings.TrimSpace(result.Stdout())
|
||||
c.Assert(id, checker.Not(checker.Equals), "")
|
||||
|
||||
// make sure task has been deployed
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
|
||||
// and make sure we have all the log lines
|
||||
waitAndAssert(c, defaultReconciliationTimeout, countLogLines(d, name), checker.Equals, 1)
|
||||
|
||||
// First, test without pretty printing
|
||||
// call service logs with details. set raw to skip pretty printing
|
||||
result = icmd.RunCmd(d.Command("service", "logs", "--raw", "--details", name))
|
||||
// in this case, we should get details and we should get log message, but
|
||||
// there will also be context as details (which will fall after the detail
|
||||
// we inserted in alphabetical order
|
||||
result.Assert(c, icmd.Expected{Out: "asdf=test1"})
|
||||
result.Assert(c, icmd.Expected{Out: "LogLine"})
|
||||
|
||||
// call service logs with details. this time, don't pass raw
|
||||
result = icmd.RunCmd(d.Command("service", "logs", "--details", id))
|
||||
// in this case, we should get details space logmessage as well. the context
|
||||
// is part of the pretty part of the logline
|
||||
result.Assert(c, icmd.Expected{Out: "asdf=test1 LogLine"})
|
||||
}
|
57
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_service_scale_test.go
generated
vendored
Normal file
57
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_service_scale_test.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceScale(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
service1Name := "TestService1"
|
||||
service1Args := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", service1Name, defaultSleepImage}, sleepCommandForDaemonPlatform()...)
|
||||
|
||||
// global mode
|
||||
service2Name := "TestService2"
|
||||
service2Args := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", service2Name, "--mode=global", defaultSleepImage}, sleepCommandForDaemonPlatform()...)
|
||||
|
||||
// Create services
|
||||
_, err := d.Cmd(service1Args...)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = d.Cmd(service2Args...)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = d.Cmd("service", "scale", "TestService1=2")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, err := d.Cmd("service", "scale", "TestService1=foobar")
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
str := fmt.Sprintf("%s: invalid replicas value %s", service1Name, "foobar")
|
||||
if !strings.Contains(out, str) {
|
||||
c.Errorf("got: %s, expected has sub string: %s", out, str)
|
||||
}
|
||||
|
||||
out, err = d.Cmd("service", "scale", "TestService1=-1")
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
str = fmt.Sprintf("%s: invalid replicas value %s", service1Name, "-1")
|
||||
if !strings.Contains(out, str) {
|
||||
c.Errorf("got: %s, expected has sub string: %s", out, str)
|
||||
}
|
||||
|
||||
// TestService2 is a global mode
|
||||
out, err = d.Cmd("service", "scale", "TestService2=2")
|
||||
c.Assert(err, checker.NotNil)
|
||||
|
||||
str = fmt.Sprintf("%s: scale can only be used with replicated mode\n", service2Name)
|
||||
if out != str {
|
||||
c.Errorf("got: %s, expected: %s", out, str)
|
||||
}
|
||||
}
|
137
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_service_update_test.go
generated
vendored
Normal file
137
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_service_update_test.go
generated
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceUpdateLabel(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name=test", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
service := d.GetService(c, "test")
|
||||
c.Assert(service.Spec.Labels, checker.HasLen, 0)
|
||||
|
||||
// add label to empty set
|
||||
out, err = d.Cmd("service", "update", "--detach", "test", "--label-add", "foo=bar")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
service = d.GetService(c, "test")
|
||||
c.Assert(service.Spec.Labels, checker.HasLen, 1)
|
||||
c.Assert(service.Spec.Labels["foo"], checker.Equals, "bar")
|
||||
|
||||
// add label to non-empty set
|
||||
out, err = d.Cmd("service", "update", "--detach", "test", "--label-add", "foo2=bar")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
service = d.GetService(c, "test")
|
||||
c.Assert(service.Spec.Labels, checker.HasLen, 2)
|
||||
c.Assert(service.Spec.Labels["foo2"], checker.Equals, "bar")
|
||||
|
||||
out, err = d.Cmd("service", "update", "--detach", "test", "--label-rm", "foo2")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
service = d.GetService(c, "test")
|
||||
c.Assert(service.Spec.Labels, checker.HasLen, 1)
|
||||
c.Assert(service.Spec.Labels["foo2"], checker.Equals, "")
|
||||
|
||||
out, err = d.Cmd("service", "update", "--detach", "test", "--label-rm", "foo")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
service = d.GetService(c, "test")
|
||||
c.Assert(service.Spec.Labels, checker.HasLen, 0)
|
||||
c.Assert(service.Spec.Labels["foo"], checker.Equals, "")
|
||||
|
||||
// now make sure we can add again
|
||||
out, err = d.Cmd("service", "update", "--detach", "test", "--label-add", "foo=bar")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
service = d.GetService(c, "test")
|
||||
c.Assert(service.Spec.Labels, checker.HasLen, 1)
|
||||
c.Assert(service.Spec.Labels["foo"], checker.Equals, "bar")
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceUpdateSecrets(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
testName := "test_secret"
|
||||
id := d.CreateSecret(c, swarm.SecretSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: testName,
|
||||
},
|
||||
Data: []byte("TESTINGDATA"),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
|
||||
testTarget := "testing"
|
||||
serviceName := "test"
|
||||
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
// add secret
|
||||
out, err = d.Cmd("service", "update", "--detach", "test", "--secret-add", fmt.Sprintf("source=%s,target=%s", testName, testTarget))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Secrets }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var refs []swarm.SecretReference
|
||||
c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
|
||||
c.Assert(refs, checker.HasLen, 1)
|
||||
|
||||
c.Assert(refs[0].SecretName, checker.Equals, testName)
|
||||
c.Assert(refs[0].File, checker.Not(checker.IsNil))
|
||||
c.Assert(refs[0].File.Name, checker.Equals, testTarget)
|
||||
|
||||
// remove
|
||||
out, err = d.Cmd("service", "update", "--detach", "test", "--secret-rm", testName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Secrets }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
|
||||
c.Assert(refs, checker.HasLen, 0)
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestServiceUpdateConfigs(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
testName := "test_config"
|
||||
id := d.CreateConfig(c, swarm.ConfigSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: testName,
|
||||
},
|
||||
Data: []byte("TESTINGDATA"),
|
||||
})
|
||||
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
|
||||
testTarget := "/testing"
|
||||
serviceName := "test"
|
||||
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
// add config
|
||||
out, err = d.Cmd("service", "update", "--detach", "test", "--config-add", fmt.Sprintf("source=%s,target=%s", testName, testTarget))
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Configs }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var refs []swarm.ConfigReference
|
||||
c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
|
||||
c.Assert(refs, checker.HasLen, 1)
|
||||
|
||||
c.Assert(refs[0].ConfigName, checker.Equals, testName)
|
||||
c.Assert(refs[0].File, checker.Not(checker.IsNil))
|
||||
c.Assert(refs[0].File.Name, checker.Equals, testTarget)
|
||||
|
||||
// remove
|
||||
out, err = d.Cmd("service", "update", "--detach", "test", "--config-rm", testName)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Configs }}", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
|
||||
c.Assert(refs, checker.HasLen, 0)
|
||||
}
|
44
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_sni_test.go
generated
vendored
Normal file
44
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_sni_test.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestClientSetsTLSServerName(c *check.C) {
|
||||
c.Skip("Flakey test")
|
||||
// there may be more than one hit to the server for each registry request
|
||||
var serverNameReceived []string
|
||||
var serverName string
|
||||
|
||||
virtualHostServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
serverNameReceived = append(serverNameReceived, r.TLS.ServerName)
|
||||
}))
|
||||
defer virtualHostServer.Close()
|
||||
// discard TLS handshake errors written by default to os.Stderr
|
||||
virtualHostServer.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
|
||||
|
||||
u, err := url.Parse(virtualHostServer.URL)
|
||||
c.Assert(err, check.IsNil)
|
||||
hostPort := u.Host
|
||||
serverName = strings.Split(hostPort, ":")[0]
|
||||
|
||||
repoName := fmt.Sprintf("%v/dockercli/image:latest", hostPort)
|
||||
cmd := exec.Command(dockerBinary, "pull", repoName)
|
||||
cmd.Run()
|
||||
|
||||
// check that the fake server was hit at least once
|
||||
c.Assert(len(serverNameReceived) > 0, check.Equals, true)
|
||||
// check that for each hit the right server name was received
|
||||
for _, item := range serverNameReceived {
|
||||
c.Check(item, check.Equals, serverName)
|
||||
}
|
||||
}
|
199
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_start_test.go
generated
vendored
Normal file
199
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_start_test.go
generated
vendored
Normal file
|
@ -0,0 +1,199 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// Regression test for https://github.com/docker/docker/issues/7843
|
||||
func (s *DockerSuite) TestStartAttachReturnsOnError(c *check.C) {
|
||||
// Windows does not support link
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "--name", "test", "busybox")
|
||||
|
||||
// Expect this to fail because the above container is stopped, this is what we want
|
||||
out, _, err := dockerCmdWithError("run", "--name", "test2", "--link", "test:test", "busybox")
|
||||
// err shouldn't be nil because container test2 try to link to stopped container
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
|
||||
ch := make(chan error)
|
||||
go func() {
|
||||
// Attempt to start attached to the container that won't start
|
||||
// This should return an error immediately since the container can't be started
|
||||
if out, _, err := dockerCmdWithError("start", "-a", "test2"); err == nil {
|
||||
ch <- fmt.Errorf("Expected error but got none:\n%s", out)
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-ch:
|
||||
c.Assert(err, check.IsNil)
|
||||
case <-time.After(5 * time.Second):
|
||||
c.Fatalf("Attach did not exit properly")
|
||||
}
|
||||
}
|
||||
|
||||
// gh#8555: Exit code should be passed through when using start -a
|
||||
func (s *DockerSuite) TestStartAttachCorrectExitCode(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out := cli.DockerCmd(c, "run", "-d", "busybox", "sh", "-c", "sleep 2; exit 1").Stdout()
|
||||
out = strings.TrimSpace(out)
|
||||
|
||||
// make sure the container has exited before trying the "start -a"
|
||||
cli.DockerCmd(c, "wait", out)
|
||||
|
||||
cli.Docker(cli.Args("start", "-a", out)).Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStartAttachSilent(c *check.C) {
|
||||
name := "teststartattachcorrectexitcode"
|
||||
dockerCmd(c, "run", "--name", name, "busybox", "echo", "test")
|
||||
|
||||
// make sure the container has exited before trying the "start -a"
|
||||
dockerCmd(c, "wait", name)
|
||||
|
||||
startOut, _ := dockerCmd(c, "start", "-a", name)
|
||||
// start -a produced unexpected output
|
||||
c.Assert(startOut, checker.Equals, "test\n")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStartRecordError(c *check.C) {
|
||||
// TODO Windows CI: Requires further porting work. Should be possible.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// when container runs successfully, we should not have state.Error
|
||||
dockerCmd(c, "run", "-d", "-p", "9999:9999", "--name", "test", "busybox", "top")
|
||||
stateErr := inspectField(c, "test", "State.Error")
|
||||
// Expected to not have state error
|
||||
c.Assert(stateErr, checker.Equals, "")
|
||||
|
||||
// Expect this to fail and records error because of ports conflict
|
||||
out, _, err := dockerCmdWithError("run", "-d", "--name", "test2", "-p", "9999:9999", "busybox", "top")
|
||||
// err shouldn't be nil because docker run will fail
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
|
||||
stateErr = inspectField(c, "test2", "State.Error")
|
||||
c.Assert(stateErr, checker.Contains, "port is already allocated")
|
||||
|
||||
// Expect the conflict to be resolved when we stop the initial container
|
||||
dockerCmd(c, "stop", "test")
|
||||
dockerCmd(c, "start", "test2")
|
||||
stateErr = inspectField(c, "test2", "State.Error")
|
||||
// Expected to not have state error but got one
|
||||
c.Assert(stateErr, checker.Equals, "")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStartPausedContainer(c *check.C) {
|
||||
// Windows does not support pausing containers
|
||||
testRequires(c, IsPausable)
|
||||
|
||||
runSleepingContainer(c, "-d", "--name", "testing")
|
||||
|
||||
dockerCmd(c, "pause", "testing")
|
||||
|
||||
out, _, err := dockerCmdWithError("start", "testing")
|
||||
// an error should have been shown that you cannot start paused container
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
// an error should have been shown that you cannot start paused container
|
||||
c.Assert(strings.ToLower(out), checker.Contains, "cannot start a paused container, try unpause instead")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStartMultipleContainers(c *check.C) {
|
||||
// Windows does not support --link
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// run a container named 'parent' and create two container link to `parent`
|
||||
dockerCmd(c, "run", "-d", "--name", "parent", "busybox", "top")
|
||||
|
||||
for _, container := range []string{"child_first", "child_second"} {
|
||||
dockerCmd(c, "create", "--name", container, "--link", "parent:parent", "busybox", "top")
|
||||
}
|
||||
|
||||
// stop 'parent' container
|
||||
dockerCmd(c, "stop", "parent")
|
||||
|
||||
out := inspectField(c, "parent", "State.Running")
|
||||
// Container should be stopped
|
||||
c.Assert(out, checker.Equals, "false")
|
||||
|
||||
// start all the three containers, container `child_first` start first which should be failed
|
||||
// container 'parent' start second and then start container 'child_second'
|
||||
expOut := "Cannot link to a non running container"
|
||||
expErr := "failed to start containers: [child_first]"
|
||||
out, _, err := dockerCmdWithError("start", "child_first", "parent", "child_second")
|
||||
// err shouldn't be nil because start will fail
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
// output does not correspond to what was expected
|
||||
if !(strings.Contains(out, expOut) || strings.Contains(err.Error(), expErr)) {
|
||||
c.Fatalf("Expected out: %v with err: %v but got out: %v with err: %v", expOut, expErr, out, err)
|
||||
}
|
||||
|
||||
for container, expected := range map[string]string{"parent": "true", "child_first": "false", "child_second": "true"} {
|
||||
out := inspectField(c, container, "State.Running")
|
||||
// Container running state wrong
|
||||
c.Assert(out, checker.Equals, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStartAttachMultipleContainers(c *check.C) {
|
||||
// run multiple containers to test
|
||||
for _, container := range []string{"test1", "test2", "test3"} {
|
||||
runSleepingContainer(c, "--name", container)
|
||||
}
|
||||
|
||||
// stop all the containers
|
||||
for _, container := range []string{"test1", "test2", "test3"} {
|
||||
dockerCmd(c, "stop", container)
|
||||
}
|
||||
|
||||
// test start and attach multiple containers at once, expected error
|
||||
for _, option := range []string{"-a", "-i", "-ai"} {
|
||||
out, _, err := dockerCmdWithError("start", option, "test1", "test2", "test3")
|
||||
// err shouldn't be nil because start will fail
|
||||
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
|
||||
// output does not correspond to what was expected
|
||||
c.Assert(out, checker.Contains, "you cannot start and attach multiple containers at once")
|
||||
}
|
||||
|
||||
// confirm the state of all the containers be stopped
|
||||
for container, expected := range map[string]string{"test1": "false", "test2": "false", "test3": "false"} {
|
||||
out := inspectField(c, container, "State.Running")
|
||||
// Container running state wrong
|
||||
c.Assert(out, checker.Equals, expected)
|
||||
}
|
||||
}
|
||||
|
||||
// Test case for #23716
|
||||
func (s *DockerSuite) TestStartAttachWithRename(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
cli.DockerCmd(c, "create", "-t", "--name", "before", "busybox")
|
||||
go func() {
|
||||
cli.WaitRun(c, "before")
|
||||
cli.DockerCmd(c, "rename", "before", "after")
|
||||
cli.DockerCmd(c, "stop", "--time=2", "after")
|
||||
}()
|
||||
// FIXME(vdemeester) the intent is not clear and potentially racey
|
||||
result := cli.Docker(cli.Args("start", "-a", "before")).Assert(c, icmd.Expected{
|
||||
ExitCode: 137,
|
||||
})
|
||||
c.Assert(result.Stderr(), checker.Not(checker.Contains), "No such container")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStartReturnCorrectExitCode(c *check.C) {
|
||||
dockerCmd(c, "create", "--restart=on-failure:2", "--name", "withRestart", "busybox", "sh", "-c", "exit 11")
|
||||
dockerCmd(c, "create", "--rm", "--name", "withRm", "busybox", "sh", "-c", "exit 12")
|
||||
|
||||
_, exitCode, err := dockerCmdWithError("start", "-a", "withRestart")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(exitCode, checker.Equals, 11)
|
||||
_, exitCode, err = dockerCmdWithError("start", "-a", "withRm")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(exitCode, checker.Equals, 12)
|
||||
}
|
180
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_stats_test.go
generated
vendored
Normal file
180
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_stats_test.go
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestStatsNoStream(c *check.C) {
|
||||
// Windows does not support stats
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), checker.IsNil)
|
||||
|
||||
statsCmd := exec.Command(dockerBinary, "stats", "--no-stream", id)
|
||||
type output struct {
|
||||
out []byte
|
||||
err error
|
||||
}
|
||||
|
||||
ch := make(chan output)
|
||||
go func() {
|
||||
out, err := statsCmd.Output()
|
||||
ch <- output{out, err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case outerr := <-ch:
|
||||
c.Assert(outerr.err, checker.IsNil, check.Commentf("Error running stats: %v", outerr.err))
|
||||
c.Assert(string(outerr.out), checker.Contains, id[:12]) //running container wasn't present in output
|
||||
case <-time.After(3 * time.Second):
|
||||
statsCmd.Process.Kill()
|
||||
c.Fatalf("stats did not return immediately when not streaming")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStatsContainerNotFound(c *check.C) {
|
||||
// Windows does not support stats
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out, _, err := dockerCmdWithError("stats", "notfound")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "No such container: notfound", check.Commentf("Expected to fail on not found container stats, got %q instead", out))
|
||||
|
||||
out, _, err = dockerCmdWithError("stats", "--no-stream", "notfound")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "No such container: notfound", check.Commentf("Expected to fail on not found container stats with --no-stream, got %q instead", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStatsAllRunningNoStream(c *check.C) {
|
||||
// Windows does not support stats
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
id1 := strings.TrimSpace(out)[:12]
|
||||
c.Assert(waitRun(id1), check.IsNil)
|
||||
out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
id2 := strings.TrimSpace(out)[:12]
|
||||
c.Assert(waitRun(id2), check.IsNil)
|
||||
out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
id3 := strings.TrimSpace(out)[:12]
|
||||
c.Assert(waitRun(id3), check.IsNil)
|
||||
dockerCmd(c, "stop", id3)
|
||||
|
||||
out, _ = dockerCmd(c, "stats", "--no-stream")
|
||||
if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
|
||||
c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
|
||||
}
|
||||
if strings.Contains(out, id3) {
|
||||
c.Fatalf("Did not expect %s in stats, got %s", id3, out)
|
||||
}
|
||||
|
||||
// check output contains real data, but not all zeros
|
||||
reg, _ := regexp.Compile("[1-9]+")
|
||||
// split output with "\n", outLines[1] is id2's output
|
||||
// outLines[2] is id1's output
|
||||
outLines := strings.Split(out, "\n")
|
||||
// check stat result of id2 contains real data
|
||||
realData := reg.Find([]byte(outLines[1][12:]))
|
||||
c.Assert(realData, checker.NotNil, check.Commentf("stat result are empty: %s", out))
|
||||
// check stat result of id1 contains real data
|
||||
realData = reg.Find([]byte(outLines[2][12:]))
|
||||
c.Assert(realData, checker.NotNil, check.Commentf("stat result are empty: %s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStatsAllNoStream(c *check.C) {
|
||||
// Windows does not support stats
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
id1 := strings.TrimSpace(out)[:12]
|
||||
c.Assert(waitRun(id1), check.IsNil)
|
||||
dockerCmd(c, "stop", id1)
|
||||
out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
id2 := strings.TrimSpace(out)[:12]
|
||||
c.Assert(waitRun(id2), check.IsNil)
|
||||
|
||||
out, _ = dockerCmd(c, "stats", "--all", "--no-stream")
|
||||
if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
|
||||
c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
|
||||
}
|
||||
|
||||
// check output contains real data, but not all zeros
|
||||
reg, _ := regexp.Compile("[1-9]+")
|
||||
// split output with "\n", outLines[1] is id2's output
|
||||
outLines := strings.Split(out, "\n")
|
||||
// check stat result of id2 contains real data
|
||||
realData := reg.Find([]byte(outLines[1][12:]))
|
||||
c.Assert(realData, checker.NotNil, check.Commentf("stat result of %s is empty: %s", id2, out))
|
||||
// check stat result of id1 contains all zero
|
||||
realData = reg.Find([]byte(outLines[2][12:]))
|
||||
c.Assert(realData, checker.IsNil, check.Commentf("stat result of %s should be empty : %s", id1, out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStatsAllNewContainersAdded(c *check.C) {
|
||||
// Windows does not support stats
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
id := make(chan string)
|
||||
addedChan := make(chan struct{})
|
||||
|
||||
runSleepingContainer(c, "-d")
|
||||
statsCmd := exec.Command(dockerBinary, "stats")
|
||||
stdout, err := statsCmd.StdoutPipe()
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(statsCmd.Start(), check.IsNil)
|
||||
go statsCmd.Wait()
|
||||
defer statsCmd.Process.Kill()
|
||||
|
||||
go func() {
|
||||
containerID := <-id
|
||||
matchID := regexp.MustCompile(containerID)
|
||||
|
||||
scanner := bufio.NewScanner(stdout)
|
||||
for scanner.Scan() {
|
||||
switch {
|
||||
case matchID.MatchString(scanner.Text()):
|
||||
close(addedChan)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
out := runSleepingContainer(c, "-d")
|
||||
c.Assert(waitRun(strings.TrimSpace(out)), check.IsNil)
|
||||
id <- strings.TrimSpace(out)[:12]
|
||||
|
||||
select {
|
||||
case <-time.After(30 * time.Second):
|
||||
c.Fatal("failed to observe new container created added to stats")
|
||||
case <-addedChan:
|
||||
// ignore, done
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestStatsFormatAll(c *check.C) {
|
||||
// Windows does not support stats
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
cli.DockerCmd(c, "run", "-d", "--name=RunningOne", "busybox", "top")
|
||||
cli.WaitRun(c, "RunningOne")
|
||||
cli.DockerCmd(c, "run", "-d", "--name=ExitedOne", "busybox", "top")
|
||||
cli.DockerCmd(c, "stop", "ExitedOne")
|
||||
cli.WaitExited(c, "ExitedOne", 5*time.Second)
|
||||
|
||||
out := cli.DockerCmd(c, "stats", "--no-stream", "--format", "{{.Name}}").Combined()
|
||||
c.Assert(out, checker.Contains, "RunningOne")
|
||||
c.Assert(out, checker.Not(checker.Contains), "ExitedOne")
|
||||
|
||||
out = cli.DockerCmd(c, "stats", "--all", "--no-stream", "--format", "{{.Name}}").Combined()
|
||||
c.Assert(out, checker.Contains, "RunningOne")
|
||||
c.Assert(out, checker.Contains, "ExitedOne")
|
||||
}
|
2067
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_swarm_test.go
generated
vendored
Normal file
2067
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_swarm_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
105
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_swarm_unix_test.go
generated
vendored
Normal file
105
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_swarm_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSwarmSuite) TestSwarmVolumePlugin(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--mount", "type=volume,source=my-volume,destination=/foo,volume-driver=customvolumedriver", "--name", "top", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
// Make sure task stays pending before plugin is available
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckServiceTasksInStateWithError("top", swarm.TaskStatePending, "missing plugin on 1 node"), checker.Equals, 1)
|
||||
|
||||
plugin := newVolumePlugin(c, "customvolumedriver")
|
||||
defer plugin.Close()
|
||||
|
||||
// create a dummy volume to trigger lazy loading of the plugin
|
||||
out, err = d.Cmd("volume", "create", "-d", "customvolumedriver", "hello")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%s", out))
|
||||
|
||||
// TODO(aaronl): It will take about 15 seconds for swarm to realize the
|
||||
// plugin was loaded. Switching the test over to plugin v2 would avoid
|
||||
// this long delay.
|
||||
|
||||
// make sure task has been deployed.
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
|
||||
|
||||
out, err = d.Cmd("ps", "-q")
|
||||
c.Assert(err, checker.IsNil)
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
out, err = d.Cmd("inspect", "-f", "{{json .Mounts}}", containerID)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
var mounts []struct {
|
||||
Name string
|
||||
Driver string
|
||||
}
|
||||
|
||||
c.Assert(json.NewDecoder(strings.NewReader(out)).Decode(&mounts), checker.IsNil)
|
||||
c.Assert(len(mounts), checker.Equals, 1, check.Commentf("%s", out))
|
||||
c.Assert(mounts[0].Name, checker.Equals, "my-volume")
|
||||
c.Assert(mounts[0].Driver, checker.Equals, "customvolumedriver")
|
||||
}
|
||||
|
||||
// Test network plugin filter in swarm
|
||||
func (s *DockerSwarmSuite) TestSwarmNetworkPluginV2(c *check.C) {
|
||||
testRequires(c, IsAmd64)
|
||||
d1 := s.AddDaemon(c, true, true)
|
||||
d2 := s.AddDaemon(c, true, false)
|
||||
|
||||
// install plugin on d1 and d2
|
||||
pluginName := "aragunathan/global-net-plugin:latest"
|
||||
|
||||
_, err := d1.Cmd("plugin", "install", pluginName, "--grant-all-permissions")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = d2.Cmd("plugin", "install", pluginName, "--grant-all-permissions")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// create network
|
||||
networkName := "globalnet"
|
||||
_, err = d1.Cmd("network", "create", "--driver", pluginName, networkName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// create a global service to ensure that both nodes will have an instance
|
||||
serviceName := "my-service"
|
||||
_, err = d1.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "--mode=global", "--network", networkName, "busybox", "top")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount), checker.Equals, 2)
|
||||
|
||||
// remove service
|
||||
_, err = d1.Cmd("service", "rm", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// wait to ensure all containers have exited before removing the plugin. Else there's a
|
||||
// possibility of container exits erroring out due to plugins being unavailable.
|
||||
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount), checker.Equals, 0)
|
||||
|
||||
// disable plugin on worker
|
||||
_, err = d2.Cmd("plugin", "disable", "-f", pluginName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
time.Sleep(20 * time.Second)
|
||||
|
||||
image := "busybox:latest"
|
||||
// create a new global service again.
|
||||
_, err = d1.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "--mode=global", "--network", networkName, image, "top")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d1.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image: 1})
|
||||
}
|
73
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_top_test.go
generated
vendored
Normal file
73
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_top_test.go
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestTopMultipleArgs(c *check.C) {
|
||||
out := runSleepingContainer(c, "-d")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
var expected icmd.Expected
|
||||
switch testEnv.OSType {
|
||||
case "windows":
|
||||
expected = icmd.Expected{ExitCode: 1, Err: "Windows does not support arguments to top"}
|
||||
default:
|
||||
expected = icmd.Expected{Out: "PID"}
|
||||
}
|
||||
result := dockerCmdWithResult("top", cleanedContainerID, "-o", "pid")
|
||||
result.Assert(c, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestTopNonPrivileged(c *check.C) {
|
||||
out := runSleepingContainer(c, "-d")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out1, _ := dockerCmd(c, "top", cleanedContainerID)
|
||||
out2, _ := dockerCmd(c, "top", cleanedContainerID)
|
||||
dockerCmd(c, "kill", cleanedContainerID)
|
||||
|
||||
// Windows will list the name of the launched executable which in this case is busybox.exe, without the parameters.
|
||||
// Linux will display the command executed in the container
|
||||
var lookingFor string
|
||||
if testEnv.OSType == "windows" {
|
||||
lookingFor = "busybox.exe"
|
||||
} else {
|
||||
lookingFor = "top"
|
||||
}
|
||||
|
||||
c.Assert(out1, checker.Contains, lookingFor, check.Commentf("top should've listed `%s` in the process list, but failed the first time", lookingFor))
|
||||
c.Assert(out2, checker.Contains, lookingFor, check.Commentf("top should've listed `%s` in the process list, but failed the second time", lookingFor))
|
||||
}
|
||||
|
||||
// TestTopWindowsCoreProcesses validates that there are lines for the critical
|
||||
// processes which are found in a Windows container. Note Windows is architecturally
|
||||
// very different to Linux in this regard.
|
||||
func (s *DockerSuite) TestTopWindowsCoreProcesses(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows)
|
||||
out := runSleepingContainer(c, "-d")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
out1, _ := dockerCmd(c, "top", cleanedContainerID)
|
||||
lookingFor := []string{"smss.exe", "csrss.exe", "wininit.exe", "services.exe", "lsass.exe", "CExecSvc.exe"}
|
||||
for i, s := range lookingFor {
|
||||
c.Assert(out1, checker.Contains, s, check.Commentf("top should've listed `%s` in the process list, but failed. Test case %d", s, i))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestTopPrivileged(c *check.C) {
|
||||
// Windows does not support --privileged
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
out, _ := dockerCmd(c, "run", "--privileged", "-i", "-d", "busybox", "top")
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
|
||||
out1, _ := dockerCmd(c, "top", cleanedContainerID)
|
||||
out2, _ := dockerCmd(c, "top", cleanedContainerID)
|
||||
dockerCmd(c, "kill", cleanedContainerID)
|
||||
|
||||
c.Assert(out1, checker.Contains, "top", check.Commentf("top should've listed `top` in the process list, but failed the first time"))
|
||||
c.Assert(out2, checker.Contains, "top", check.Commentf("top should've listed `top` in the process list, but failed the second time"))
|
||||
}
|
339
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_update_unix_test.go
generated
vendored
Normal file
339
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_update_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,339 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/go-check/check"
|
||||
"github.com/kr/pty"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestUpdateRunningContainer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "top")
|
||||
dockerCmd(c, "update", "-m", "500M", name)
|
||||
|
||||
c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "524288000")
|
||||
|
||||
file := "/sys/fs/cgroup/memory/memory.limit_in_bytes"
|
||||
out, _ := dockerCmd(c, "exec", name, "cat", file)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "524288000")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateRunningContainerWithRestart(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "top")
|
||||
dockerCmd(c, "update", "-m", "500M", name)
|
||||
dockerCmd(c, "restart", name)
|
||||
|
||||
c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "524288000")
|
||||
|
||||
file := "/sys/fs/cgroup/memory/memory.limit_in_bytes"
|
||||
out, _ := dockerCmd(c, "exec", name, "cat", file)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "524288000")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateStoppedContainer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
|
||||
name := "test-update-container"
|
||||
file := "/sys/fs/cgroup/memory/memory.limit_in_bytes"
|
||||
dockerCmd(c, "run", "--name", name, "-m", "300M", "busybox", "cat", file)
|
||||
dockerCmd(c, "update", "-m", "500M", name)
|
||||
|
||||
c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "524288000")
|
||||
|
||||
out, _ := dockerCmd(c, "start", "-a", name)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "524288000")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdatePausedContainer(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, cpuShare)
|
||||
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "--cpu-shares", "1000", "busybox", "top")
|
||||
dockerCmd(c, "pause", name)
|
||||
dockerCmd(c, "update", "--cpu-shares", "500", name)
|
||||
|
||||
c.Assert(inspectField(c, name, "HostConfig.CPUShares"), checker.Equals, "500")
|
||||
|
||||
dockerCmd(c, "unpause", name)
|
||||
file := "/sys/fs/cgroup/cpu/cpu.shares"
|
||||
out, _ := dockerCmd(c, "exec", name, "cat", file)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "500")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateWithUntouchedFields(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
testRequires(c, cpuShare)
|
||||
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "--cpu-shares", "800", "busybox", "top")
|
||||
dockerCmd(c, "update", "-m", "500M", name)
|
||||
|
||||
// Update memory and not touch cpus, `cpuset.cpus` should still have the old value
|
||||
out := inspectField(c, name, "HostConfig.CPUShares")
|
||||
c.Assert(out, check.Equals, "800")
|
||||
|
||||
file := "/sys/fs/cgroup/cpu/cpu.shares"
|
||||
out, _ = dockerCmd(c, "exec", name, "cat", file)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "800")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateContainerInvalidValue(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "true")
|
||||
out, _, err := dockerCmdWithError("update", "-m", "2M", name)
|
||||
c.Assert(err, check.NotNil)
|
||||
expected := "Minimum memory limit allowed is 4MB"
|
||||
c.Assert(out, checker.Contains, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateContainerWithoutFlags(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "true")
|
||||
_, _, err := dockerCmdWithError("update", name)
|
||||
c.Assert(err, check.NotNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateKernelMemory(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, kernelMemorySupport)
|
||||
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "--kernel-memory", "50M", "busybox", "top")
|
||||
dockerCmd(c, "update", "--kernel-memory", "100M", name)
|
||||
|
||||
c.Assert(inspectField(c, name, "HostConfig.KernelMemory"), checker.Equals, "104857600")
|
||||
|
||||
file := "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes"
|
||||
out, _ := dockerCmd(c, "exec", name, "cat", file)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "104857600")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateKernelMemoryUninitialized(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, kernelMemorySupport)
|
||||
|
||||
isNewKernel := CheckKernelVersion(4, 6, 0)
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "busybox", "top")
|
||||
_, _, err := dockerCmdWithError("update", "--kernel-memory", "100M", name)
|
||||
// Update kernel memory to a running container without kernel memory initialized
|
||||
// is not allowed before kernel version 4.6.
|
||||
if !isNewKernel {
|
||||
c.Assert(err, check.NotNil)
|
||||
} else {
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
dockerCmd(c, "pause", name)
|
||||
_, _, err = dockerCmdWithError("update", "--kernel-memory", "200M", name)
|
||||
if !isNewKernel {
|
||||
c.Assert(err, check.NotNil)
|
||||
} else {
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
dockerCmd(c, "unpause", name)
|
||||
|
||||
dockerCmd(c, "stop", name)
|
||||
dockerCmd(c, "update", "--kernel-memory", "300M", name)
|
||||
dockerCmd(c, "start", name)
|
||||
|
||||
c.Assert(inspectField(c, name, "HostConfig.KernelMemory"), checker.Equals, "314572800")
|
||||
|
||||
file := "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes"
|
||||
out, _ := dockerCmd(c, "exec", name, "cat", file)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "314572800")
|
||||
}
|
||||
|
||||
// GetKernelVersion gets the current kernel version.
|
||||
func GetKernelVersion() *kernel.VersionInfo {
|
||||
v, _ := kernel.ParseRelease(testEnv.DaemonInfo.KernelVersion)
|
||||
return v
|
||||
}
|
||||
|
||||
// CheckKernelVersion checks if current kernel is newer than (or equal to)
|
||||
// the given version.
|
||||
func CheckKernelVersion(k, major, minor int) bool {
|
||||
return kernel.CompareKernelVersion(*GetKernelVersion(), kernel.VersionInfo{Kernel: k, Major: major, Minor: minor}) >= 0
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateSwapMemoryOnly(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
testRequires(c, swapMemorySupport)
|
||||
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "--memory", "300M", "--memory-swap", "500M", "busybox", "top")
|
||||
dockerCmd(c, "update", "--memory-swap", "600M", name)
|
||||
|
||||
c.Assert(inspectField(c, name, "HostConfig.MemorySwap"), checker.Equals, "629145600")
|
||||
|
||||
file := "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"
|
||||
out, _ := dockerCmd(c, "exec", name, "cat", file)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "629145600")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateInvalidSwapMemory(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
testRequires(c, swapMemorySupport)
|
||||
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "--memory", "300M", "--memory-swap", "500M", "busybox", "top")
|
||||
_, _, err := dockerCmdWithError("update", "--memory-swap", "200M", name)
|
||||
// Update invalid swap memory should fail.
|
||||
// This will pass docker config validation, but failed at kernel validation
|
||||
c.Assert(err, check.NotNil)
|
||||
|
||||
// Update invalid swap memory with failure should not change HostConfig
|
||||
c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "314572800")
|
||||
c.Assert(inspectField(c, name, "HostConfig.MemorySwap"), checker.Equals, "524288000")
|
||||
|
||||
dockerCmd(c, "update", "--memory-swap", "600M", name)
|
||||
|
||||
c.Assert(inspectField(c, name, "HostConfig.MemorySwap"), checker.Equals, "629145600")
|
||||
|
||||
file := "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"
|
||||
out, _ := dockerCmd(c, "exec", name, "cat", file)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "629145600")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateStats(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
testRequires(c, cpuCfsQuota)
|
||||
name := "foo"
|
||||
dockerCmd(c, "run", "-d", "-ti", "--name", name, "-m", "500m", "busybox")
|
||||
|
||||
c.Assert(waitRun(name), checker.IsNil)
|
||||
|
||||
getMemLimit := func(id string) uint64 {
|
||||
resp, body, err := request.Get(fmt.Sprintf("/containers/%s/stats?stream=false", id))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.Header.Get("Content-Type"), checker.Equals, "application/json")
|
||||
|
||||
var v *types.Stats
|
||||
err = json.NewDecoder(body).Decode(&v)
|
||||
c.Assert(err, checker.IsNil)
|
||||
body.Close()
|
||||
|
||||
return v.MemoryStats.Limit
|
||||
}
|
||||
preMemLimit := getMemLimit(name)
|
||||
|
||||
dockerCmd(c, "update", "--cpu-quota", "2000", name)
|
||||
|
||||
curMemLimit := getMemLimit(name)
|
||||
|
||||
c.Assert(preMemLimit, checker.Equals, curMemLimit)
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateMemoryWithSwapMemory(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
testRequires(c, swapMemorySupport)
|
||||
|
||||
name := "test-update-container"
|
||||
dockerCmd(c, "run", "-d", "--name", name, "--memory", "300M", "busybox", "top")
|
||||
out, _, err := dockerCmdWithError("update", "--memory", "800M", name)
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "Memory limit should be smaller than already set memoryswap limit")
|
||||
|
||||
dockerCmd(c, "update", "--memory", "800M", "--memory-swap", "1000M", name)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateNotAffectMonitorRestartPolicy(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, cpuShare)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-tid", "--restart=always", "busybox", "sh")
|
||||
id := strings.TrimSpace(string(out))
|
||||
dockerCmd(c, "update", "--cpu-shares", "512", id)
|
||||
|
||||
cpty, tty, err := pty.Open()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cpty.Close()
|
||||
|
||||
cmd := exec.Command(dockerBinary, "attach", id)
|
||||
cmd.Stdin = tty
|
||||
|
||||
c.Assert(cmd.Start(), checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
_, err = cpty.Write([]byte("exit\n"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(cmd.Wait(), checker.IsNil)
|
||||
|
||||
// container should restart again and keep running
|
||||
err = waitInspect(id, "{{.RestartCount}}", "1", 30*time.Second)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(waitRun(id), checker.IsNil)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestUpdateWithNanoCPUs(c *check.C) {
|
||||
testRequires(c, cpuCfsQuota, cpuCfsPeriod)
|
||||
|
||||
file1 := "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"
|
||||
file2 := "/sys/fs/cgroup/cpu/cpu.cfs_period_us"
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "--cpus", "0.5", "--name", "top", "busybox", "top")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
|
||||
out, _ = dockerCmd(c, "exec", "top", "sh", "-c", fmt.Sprintf("cat %s && cat %s", file1, file2))
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "50000\n100000")
|
||||
|
||||
clt, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
inspect, err := clt.ContainerInspect(context.Background(), "top")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(inspect.HostConfig.NanoCPUs, checker.Equals, int64(500000000))
|
||||
|
||||
out = inspectField(c, "top", "HostConfig.CpuQuota")
|
||||
c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS quota should be 0"))
|
||||
out = inspectField(c, "top", "HostConfig.CpuPeriod")
|
||||
c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS period should be 0"))
|
||||
|
||||
out, _, err = dockerCmdWithError("update", "--cpu-quota", "80000", "top")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set")
|
||||
|
||||
dockerCmd(c, "update", "--cpus", "0.8", "top")
|
||||
inspect, err = clt.ContainerInspect(context.Background(), "top")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(inspect.HostConfig.NanoCPUs, checker.Equals, int64(800000000))
|
||||
|
||||
out = inspectField(c, "top", "HostConfig.CpuQuota")
|
||||
c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS quota should be 0"))
|
||||
out = inspectField(c, "top", "HostConfig.CpuPeriod")
|
||||
c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS period should be 0"))
|
||||
|
||||
out, _ = dockerCmd(c, "exec", "top", "sh", "-c", fmt.Sprintf("cat %s && cat %s", file1, file2))
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "80000\n100000")
|
||||
}
|
98
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_userns_test.go
generated
vendored
Normal file
98
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_userns_test.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// user namespaces test: run daemon with remapped root setting
|
||||
// 1. validate uid/gid maps are set properly
|
||||
// 2. verify that files created are owned by remapped root
|
||||
func (s *DockerDaemonSuite) TestDaemonUserNamespaceRootSetting(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon, UserNamespaceInKernel)
|
||||
|
||||
s.d.StartWithBusybox(c, "--userns-remap", "default")
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "userns")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
// Set a non-existent path
|
||||
tmpDirNotExists := path.Join(os.TempDir(), "userns"+stringid.GenerateRandomID())
|
||||
defer os.RemoveAll(tmpDirNotExists)
|
||||
|
||||
// we need to find the uid and gid of the remapped root from the daemon's root dir info
|
||||
uidgid := strings.Split(filepath.Base(s.d.Root), ".")
|
||||
c.Assert(uidgid, checker.HasLen, 2, check.Commentf("Should have gotten uid/gid strings from root dirname: %s", filepath.Base(s.d.Root)))
|
||||
uid, err := strconv.Atoi(uidgid[0])
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Can't parse uid"))
|
||||
gid, err := strconv.Atoi(uidgid[1])
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Can't parse gid"))
|
||||
|
||||
// writable by the remapped root UID/GID pair
|
||||
c.Assert(os.Chown(tmpDir, uid, gid), checker.IsNil)
|
||||
|
||||
out, err := s.d.Cmd("run", "-d", "--name", "userns", "-v", tmpDir+":/goofy", "-v", tmpDirNotExists+":/donald", "busybox", "sh", "-c", "touch /goofy/testfile; top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Output: %s", out))
|
||||
user := s.findUser(c, "userns")
|
||||
c.Assert(uidgid[0], checker.Equals, user)
|
||||
|
||||
// check that the created directory is owned by remapped uid:gid
|
||||
statNotExists, err := system.Stat(tmpDirNotExists)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(statNotExists.UID(), checker.Equals, uint32(uid), check.Commentf("Created directory not owned by remapped root UID"))
|
||||
c.Assert(statNotExists.GID(), checker.Equals, uint32(gid), check.Commentf("Created directory not owned by remapped root GID"))
|
||||
|
||||
pid, err := s.d.Cmd("inspect", "--format={{.State.Pid}}", "userns")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Could not inspect running container: out: %q", pid))
|
||||
// check the uid and gid maps for the PID to ensure root is remapped
|
||||
// (cmd = cat /proc/<pid>/uid_map | grep -E '0\s+9999\s+1')
|
||||
_, err = RunCommandPipelineWithOutput(
|
||||
exec.Command("cat", "/proc/"+strings.TrimSpace(pid)+"/uid_map"),
|
||||
exec.Command("grep", "-E", fmt.Sprintf("0[[:space:]]+%d[[:space:]]+", uid)))
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
_, err = RunCommandPipelineWithOutput(
|
||||
exec.Command("cat", "/proc/"+strings.TrimSpace(pid)+"/gid_map"),
|
||||
exec.Command("grep", "-E", fmt.Sprintf("0[[:space:]]+%d[[:space:]]+", gid)))
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// check that the touched file is owned by remapped uid:gid
|
||||
stat, err := system.Stat(filepath.Join(tmpDir, "testfile"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(stat.UID(), checker.Equals, uint32(uid), check.Commentf("Touched file not owned by remapped root UID"))
|
||||
c.Assert(stat.GID(), checker.Equals, uint32(gid), check.Commentf("Touched file not owned by remapped root GID"))
|
||||
|
||||
// use host usernamespace
|
||||
out, err = s.d.Cmd("run", "-d", "--name", "userns_skip", "--userns", "host", "busybox", "sh", "-c", "touch /goofy/testfile; top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Output: %s", out))
|
||||
user = s.findUser(c, "userns_skip")
|
||||
// userns are skipped, user is root
|
||||
c.Assert(user, checker.Equals, "root")
|
||||
}
|
||||
|
||||
// findUser finds the uid or name of the user of the first process that runs in a container
|
||||
func (s *DockerDaemonSuite) findUser(c *check.C, container string) string {
|
||||
out, err := s.d.Cmd("top", container)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Output: %s", out))
|
||||
rows := strings.Split(out, "\n")
|
||||
if len(rows) < 2 {
|
||||
// No process rows founds
|
||||
c.FailNow()
|
||||
}
|
||||
return strings.Fields(rows[1])[0]
|
||||
}
|
58
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_v2_only_test.go
generated
vendored
Normal file
58
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_v2_only_test.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/internal/test/registry"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func makefile(path string, contents string) (string, error) {
|
||||
f, err := ioutil.TempFile(path, "tmp")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = ioutil.WriteFile(f.Name(), []byte(contents), os.ModePerm)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return f.Name(), nil
|
||||
}
|
||||
|
||||
// TestV2Only ensures that a daemon does not
|
||||
// attempt to contact any v1 registry endpoints.
|
||||
func (s *DockerRegistrySuite) TestV2Only(c *check.C) {
|
||||
reg, err := registry.NewMock(c)
|
||||
defer reg.Close()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(404)
|
||||
})
|
||||
|
||||
reg.RegisterHandler("/v1/.*", func(w http.ResponseWriter, r *http.Request) {
|
||||
c.Fatal("V1 registry contacted")
|
||||
})
|
||||
|
||||
repoName := fmt.Sprintf("%s/busybox", reg.URL())
|
||||
|
||||
s.d.Start(c, "--insecure-registry", reg.URL())
|
||||
|
||||
tmp, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, check.IsNil)
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
dockerfileName, err := makefile(tmp, fmt.Sprintf("FROM %s/busybox", reg.URL()))
|
||||
c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile"))
|
||||
|
||||
s.d.Cmd("build", "--file", dockerfileName, tmp)
|
||||
|
||||
s.d.Cmd("run", repoName)
|
||||
s.d.Cmd("login", "-u", "richard", "-p", "testtest", reg.URL())
|
||||
s.d.Cmd("tag", "busybox", repoName)
|
||||
s.d.Cmd("push", repoName)
|
||||
s.d.Cmd("pull", repoName)
|
||||
}
|
639
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_volume_test.go
generated
vendored
Normal file
639
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_volume_test.go
generated
vendored
Normal file
|
@ -0,0 +1,639 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"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/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLICreate(c *check.C) {
|
||||
dockerCmd(c, "volume", "create")
|
||||
|
||||
_, _, err := dockerCmdWithError("volume", "create", "-d", "nosuchdriver")
|
||||
c.Assert(err, check.NotNil)
|
||||
|
||||
// test using hidden --name option
|
||||
out, _ := dockerCmd(c, "volume", "create", "--name=test")
|
||||
name := strings.TrimSpace(out)
|
||||
c.Assert(name, check.Equals, "test")
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "create", "test2")
|
||||
name = strings.TrimSpace(out)
|
||||
c.Assert(name, check.Equals, "test2")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLIInspect(c *check.C) {
|
||||
c.Assert(
|
||||
exec.Command(dockerBinary, "volume", "inspect", "doesnotexist").Run(),
|
||||
check.Not(check.IsNil),
|
||||
check.Commentf("volume inspect should error on non-existent volume"),
|
||||
)
|
||||
|
||||
out, _ := dockerCmd(c, "volume", "create")
|
||||
name := strings.TrimSpace(out)
|
||||
out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Name }}", name)
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, name)
|
||||
|
||||
dockerCmd(c, "volume", "create", "test")
|
||||
out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Name }}", "test")
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, "test")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLIInspectMulti(c *check.C) {
|
||||
dockerCmd(c, "volume", "create", "test1")
|
||||
dockerCmd(c, "volume", "create", "test2")
|
||||
dockerCmd(c, "volume", "create", "test3")
|
||||
|
||||
result := dockerCmdWithResult("volume", "inspect", "--format={{ .Name }}", "test1", "test2", "doesnotexist", "test3")
|
||||
result.Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: "No such volume: doesnotexist",
|
||||
})
|
||||
|
||||
out := result.Stdout()
|
||||
c.Assert(out, checker.Contains, "test1")
|
||||
c.Assert(out, checker.Contains, "test2")
|
||||
c.Assert(out, checker.Contains, "test3")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLILs(c *check.C) {
|
||||
prefix, _ := getPrefixAndSlashFromDaemonPlatform()
|
||||
dockerCmd(c, "volume", "create", "aaa")
|
||||
|
||||
dockerCmd(c, "volume", "create", "test")
|
||||
|
||||
dockerCmd(c, "volume", "create", "soo")
|
||||
dockerCmd(c, "run", "-v", "soo:"+prefix+"/foo", "busybox", "ls", "/")
|
||||
|
||||
out, _ := dockerCmd(c, "volume", "ls", "-q")
|
||||
assertVolumesInList(c, out, []string{"aaa", "soo", "test"})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeLsFormat(c *check.C) {
|
||||
dockerCmd(c, "volume", "create", "aaa")
|
||||
dockerCmd(c, "volume", "create", "test")
|
||||
dockerCmd(c, "volume", "create", "soo")
|
||||
|
||||
out, _ := dockerCmd(c, "volume", "ls", "--format", "{{.Name}}")
|
||||
assertVolumesInList(c, out, []string{"aaa", "soo", "test"})
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeLsFormatDefaultFormat(c *check.C) {
|
||||
dockerCmd(c, "volume", "create", "aaa")
|
||||
dockerCmd(c, "volume", "create", "test")
|
||||
dockerCmd(c, "volume", "create", "soo")
|
||||
|
||||
config := `{
|
||||
"volumesFormat": "{{ .Name }} default"
|
||||
}`
|
||||
d, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "--config", d, "volume", "ls")
|
||||
assertVolumesInList(c, out, []string{"aaa default", "soo default", "test default"})
|
||||
}
|
||||
|
||||
// assertVolList checks volume retrieved with ls command
|
||||
// equals to expected volume list
|
||||
// note: out should be `volume ls [option]` result
|
||||
func assertVolList(c *check.C, out string, expectVols []string) {
|
||||
lines := strings.Split(out, "\n")
|
||||
var volList []string
|
||||
for _, line := range lines[1 : len(lines)-1] {
|
||||
volFields := strings.Fields(line)
|
||||
// wrap all volume name in volList
|
||||
volList = append(volList, volFields[1])
|
||||
}
|
||||
|
||||
// volume ls should contains all expected volumes
|
||||
c.Assert(volList, checker.DeepEquals, expectVols)
|
||||
}
|
||||
|
||||
func assertVolumesInList(c *check.C, out string, expected []string) {
|
||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
for _, expect := range expected {
|
||||
found := false
|
||||
for _, v := range lines {
|
||||
found = v == expect
|
||||
if found {
|
||||
break
|
||||
}
|
||||
}
|
||||
c.Assert(found, checker.Equals, true, check.Commentf("Expected volume not found: %v, got: %v", expect, lines))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLILsFilterDangling(c *check.C) {
|
||||
prefix, _ := getPrefixAndSlashFromDaemonPlatform()
|
||||
dockerCmd(c, "volume", "create", "testnotinuse1")
|
||||
dockerCmd(c, "volume", "create", "testisinuse1")
|
||||
dockerCmd(c, "volume", "create", "testisinuse2")
|
||||
|
||||
// Make sure both "created" (but not started), and started
|
||||
// containers are included in reference counting
|
||||
dockerCmd(c, "run", "--name", "volume-test1", "-v", "testisinuse1:"+prefix+"/foo", "busybox", "true")
|
||||
dockerCmd(c, "create", "--name", "volume-test2", "-v", "testisinuse2:"+prefix+"/foo", "busybox", "true")
|
||||
|
||||
out, _ := dockerCmd(c, "volume", "ls")
|
||||
|
||||
// No filter, all volumes should show
|
||||
c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
|
||||
c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
|
||||
c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=false")
|
||||
|
||||
// Explicitly disabling dangling
|
||||
c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
|
||||
c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
|
||||
c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=true")
|
||||
|
||||
// Filter "dangling" volumes; only "dangling" (unused) volumes should be in the output
|
||||
c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
|
||||
c.Assert(out, check.Not(checker.Contains), "testisinuse1\n", check.Commentf("volume 'testisinuse1' in output, but not expected"))
|
||||
c.Assert(out, check.Not(checker.Contains), "testisinuse2\n", check.Commentf("volume 'testisinuse2' in output, but not expected"))
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=1")
|
||||
// Filter "dangling" volumes; only "dangling" (unused) volumes should be in the output, dangling also accept 1
|
||||
c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
|
||||
c.Assert(out, check.Not(checker.Contains), "testisinuse1\n", check.Commentf("volume 'testisinuse1' in output, but not expected"))
|
||||
c.Assert(out, check.Not(checker.Contains), "testisinuse2\n", check.Commentf("volume 'testisinuse2' in output, but not expected"))
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=0")
|
||||
// dangling=0 is same as dangling=false case
|
||||
c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
|
||||
c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
|
||||
c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "name=testisin")
|
||||
c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
|
||||
c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
|
||||
c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLILsErrorWithInvalidFilterName(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("volume", "ls", "-f", "FOO=123")
|
||||
c.Assert(err, checker.NotNil)
|
||||
c.Assert(out, checker.Contains, "Invalid filter")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLILsWithIncorrectFilterValue(c *check.C) {
|
||||
out, _, err := dockerCmdWithError("volume", "ls", "-f", "dangling=invalid")
|
||||
c.Assert(err, check.NotNil)
|
||||
c.Assert(out, checker.Contains, "Invalid filter")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLIRm(c *check.C) {
|
||||
prefix, _ := getPrefixAndSlashFromDaemonPlatform()
|
||||
out, _ := dockerCmd(c, "volume", "create")
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "volume", "create", "test")
|
||||
dockerCmd(c, "volume", "rm", id)
|
||||
dockerCmd(c, "volume", "rm", "test")
|
||||
|
||||
volumeID := "testing"
|
||||
dockerCmd(c, "run", "-v", volumeID+":"+prefix+"/foo", "--name=test", "busybox", "sh", "-c", "echo hello > /foo/bar")
|
||||
|
||||
icmd.RunCommand(dockerBinary, "volume", "rm", "testing").Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Error: "exit status 1",
|
||||
})
|
||||
|
||||
out, _ = dockerCmd(c, "run", "--volumes-from=test", "--name=test2", "busybox", "sh", "-c", "cat /foo/bar")
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, "hello")
|
||||
dockerCmd(c, "rm", "-fv", "test2")
|
||||
dockerCmd(c, "volume", "inspect", volumeID)
|
||||
dockerCmd(c, "rm", "-f", "test")
|
||||
|
||||
out, _ = dockerCmd(c, "run", "--name=test2", "-v", volumeID+":"+prefix+"/foo", "busybox", "sh", "-c", "cat /foo/bar")
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, "hello", check.Commentf("volume data was removed"))
|
||||
dockerCmd(c, "rm", "test2")
|
||||
|
||||
dockerCmd(c, "volume", "rm", volumeID)
|
||||
c.Assert(
|
||||
exec.Command("volume", "rm", "doesnotexist").Run(),
|
||||
check.Not(check.IsNil),
|
||||
check.Commentf("volume rm should fail with non-existent volume"),
|
||||
)
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) should be a unit test in cli/command/volume package
|
||||
func (s *DockerSuite) TestVolumeCLINoArgs(c *check.C) {
|
||||
out, _ := dockerCmd(c, "volume")
|
||||
// no args should produce the cmd usage output
|
||||
usage := "Usage: docker volume COMMAND"
|
||||
c.Assert(out, checker.Contains, usage)
|
||||
|
||||
// invalid arg should error and show the command usage on stderr
|
||||
icmd.RunCommand(dockerBinary, "volume", "somearg").Assert(c, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Error: "exit status 1",
|
||||
Err: usage,
|
||||
})
|
||||
|
||||
// invalid flag should error and show the flag error and cmd usage
|
||||
result := icmd.RunCommand(dockerBinary, "volume", "--no-such-flag")
|
||||
result.Assert(c, icmd.Expected{
|
||||
ExitCode: 125,
|
||||
Error: "exit status 125",
|
||||
Err: usage,
|
||||
})
|
||||
c.Assert(result.Stderr(), checker.Contains, "unknown flag: --no-such-flag")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLIInspectTmplError(c *check.C) {
|
||||
out, _ := dockerCmd(c, "volume", "create")
|
||||
name := strings.TrimSpace(out)
|
||||
|
||||
out, exitCode, err := dockerCmdWithError("volume", "inspect", "--format='{{ .FooBar }}'", name)
|
||||
c.Assert(err, checker.NotNil, check.Commentf("Output: %s", out))
|
||||
c.Assert(exitCode, checker.Equals, 1, check.Commentf("Output: %s", out))
|
||||
c.Assert(out, checker.Contains, "Template parsing error")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLICreateWithOpts(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
dockerCmd(c, "volume", "create", "-d", "local", "test", "--opt=type=tmpfs", "--opt=device=tmpfs", "--opt=o=size=1m,uid=1000")
|
||||
out, _ := dockerCmd(c, "run", "-v", "test:/foo", "busybox", "mount")
|
||||
|
||||
mounts := strings.Split(out, "\n")
|
||||
var found bool
|
||||
for _, m := range mounts {
|
||||
if strings.Contains(m, "/foo") {
|
||||
found = true
|
||||
info := strings.Fields(m)
|
||||
// tmpfs on <path> type tmpfs (rw,relatime,size=1024k,uid=1000)
|
||||
c.Assert(info[0], checker.Equals, "tmpfs")
|
||||
c.Assert(info[2], checker.Equals, "/foo")
|
||||
c.Assert(info[4], checker.Equals, "tmpfs")
|
||||
c.Assert(info[5], checker.Contains, "uid=1000")
|
||||
c.Assert(info[5], checker.Contains, "size=1024k")
|
||||
break
|
||||
}
|
||||
}
|
||||
c.Assert(found, checker.Equals, true)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLICreateLabel(c *check.C) {
|
||||
testVol := "testvolcreatelabel"
|
||||
testLabel := "foo"
|
||||
testValue := "bar"
|
||||
|
||||
_, _, err := dockerCmdWithError("volume", "create", "--label", testLabel+"="+testValue, testVol)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "volume", "inspect", "--format={{ .Labels."+testLabel+" }}", testVol)
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, testValue)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLICreateLabelMultiple(c *check.C) {
|
||||
testVol := "testvolcreatelabel"
|
||||
|
||||
testLabels := map[string]string{
|
||||
"foo": "bar",
|
||||
"baz": "foo",
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"volume",
|
||||
"create",
|
||||
testVol,
|
||||
}
|
||||
|
||||
for k, v := range testLabels {
|
||||
args = append(args, "--label", k+"="+v)
|
||||
}
|
||||
|
||||
_, _, err := dockerCmdWithError(args...)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
for k, v := range testLabels {
|
||||
out, _ := dockerCmd(c, "volume", "inspect", "--format={{ .Labels."+k+" }}", testVol)
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, v)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLILsFilterLabels(c *check.C) {
|
||||
testVol1 := "testvolcreatelabel-1"
|
||||
_, _, err := dockerCmdWithError("volume", "create", "--label", "foo=bar1", testVol1)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
testVol2 := "testvolcreatelabel-2"
|
||||
_, _, err = dockerCmdWithError("volume", "create", "--label", "foo=bar2", testVol2)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "volume", "ls", "--filter", "label=foo")
|
||||
|
||||
// filter with label=key
|
||||
c.Assert(out, checker.Contains, "testvolcreatelabel-1\n", check.Commentf("expected volume 'testvolcreatelabel-1' in output"))
|
||||
c.Assert(out, checker.Contains, "testvolcreatelabel-2\n", check.Commentf("expected volume 'testvolcreatelabel-2' in output"))
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo=bar1")
|
||||
|
||||
// filter with label=key=value
|
||||
c.Assert(out, checker.Contains, "testvolcreatelabel-1\n", check.Commentf("expected volume 'testvolcreatelabel-1' in output"))
|
||||
c.Assert(out, check.Not(checker.Contains), "testvolcreatelabel-2\n", check.Commentf("expected volume 'testvolcreatelabel-2 in output"))
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=non-exist")
|
||||
outArr := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo=non-exist")
|
||||
outArr = strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLILsFilterDrivers(c *check.C) {
|
||||
// using default volume driver local to create volumes
|
||||
testVol1 := "testvol-1"
|
||||
_, _, err := dockerCmdWithError("volume", "create", testVol1)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
testVol2 := "testvol-2"
|
||||
_, _, err = dockerCmdWithError("volume", "create", testVol2)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// filter with driver=local
|
||||
out, _ := dockerCmd(c, "volume", "ls", "--filter", "driver=local")
|
||||
c.Assert(out, checker.Contains, "testvol-1\n", check.Commentf("expected volume 'testvol-1' in output"))
|
||||
c.Assert(out, checker.Contains, "testvol-2\n", check.Commentf("expected volume 'testvol-2' in output"))
|
||||
|
||||
// filter with driver=invaliddriver
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=invaliddriver")
|
||||
outArr := strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
|
||||
|
||||
// filter with driver=loca
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=loca")
|
||||
outArr = strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
|
||||
|
||||
// filter with driver=
|
||||
out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=")
|
||||
outArr = strings.Split(strings.TrimSpace(out), "\n")
|
||||
c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLIRmForceUsage(c *check.C) {
|
||||
out, _ := dockerCmd(c, "volume", "create")
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
dockerCmd(c, "volume", "rm", "-f", id)
|
||||
dockerCmd(c, "volume", "rm", "--force", "nonexist")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCLIRmForce(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
name := "test"
|
||||
out, _ := dockerCmd(c, "volume", "create", name)
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(id, checker.Equals, name)
|
||||
|
||||
out, _ = dockerCmd(c, "volume", "inspect", "--format", "{{.Mountpoint}}", name)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
// Mountpoint is in the form of "/var/lib/docker/volumes/.../_data", removing `/_data`
|
||||
path := strings.TrimSuffix(strings.TrimSpace(out), "/_data")
|
||||
icmd.RunCommand("rm", "-rf", path).Assert(c, icmd.Success)
|
||||
|
||||
dockerCmd(c, "volume", "rm", "-f", name)
|
||||
out, _ = dockerCmd(c, "volume", "ls")
|
||||
c.Assert(out, checker.Not(checker.Contains), name)
|
||||
dockerCmd(c, "volume", "create", name)
|
||||
out, _ = dockerCmd(c, "volume", "ls")
|
||||
c.Assert(out, checker.Contains, name)
|
||||
}
|
||||
|
||||
// TestVolumeCLIRmForceInUse verifies that repeated `docker volume rm -f` calls does not remove a volume
|
||||
// if it is in use. Test case for https://github.com/docker/docker/issues/31446
|
||||
func (s *DockerSuite) TestVolumeCLIRmForceInUse(c *check.C) {
|
||||
name := "testvolume"
|
||||
out, _ := dockerCmd(c, "volume", "create", name)
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(id, checker.Equals, name)
|
||||
|
||||
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
||||
out, _ = dockerCmd(c, "create", "-v", "testvolume:"+prefix+slash+"foo", "busybox")
|
||||
cid := strings.TrimSpace(out)
|
||||
|
||||
_, _, err := dockerCmdWithError("volume", "rm", "-f", name)
|
||||
c.Assert(err, check.NotNil)
|
||||
c.Assert(err.Error(), checker.Contains, "volume is in use")
|
||||
out, _ = dockerCmd(c, "volume", "ls")
|
||||
c.Assert(out, checker.Contains, name)
|
||||
|
||||
// The original issue did not _remove_ the volume from the list
|
||||
// the first time. But a second call to `volume rm` removed it.
|
||||
// Calling `volume rm` a second time to confirm it's not removed
|
||||
// when calling twice.
|
||||
_, _, err = dockerCmdWithError("volume", "rm", "-f", name)
|
||||
c.Assert(err, check.NotNil)
|
||||
c.Assert(err.Error(), checker.Contains, "volume is in use")
|
||||
out, _ = dockerCmd(c, "volume", "ls")
|
||||
c.Assert(out, checker.Contains, name)
|
||||
|
||||
// Verify removing the volume after the container is removed works
|
||||
_, e := dockerCmd(c, "rm", cid)
|
||||
c.Assert(e, check.Equals, 0)
|
||||
|
||||
_, e = dockerCmd(c, "volume", "rm", "-f", name)
|
||||
c.Assert(e, check.Equals, 0)
|
||||
|
||||
out, e = dockerCmd(c, "volume", "ls")
|
||||
c.Assert(e, check.Equals, 0)
|
||||
c.Assert(out, checker.Not(checker.Contains), name)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// Without options
|
||||
name := "test1"
|
||||
dockerCmd(c, "volume", "create", "-d", "local", name)
|
||||
out, _ := dockerCmd(c, "volume", "inspect", "--format={{ .Options }}", name)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "map[]")
|
||||
|
||||
// With options
|
||||
name = "test2"
|
||||
k1, v1 := "type", "tmpfs"
|
||||
k2, v2 := "device", "tmpfs"
|
||||
k3, v3 := "o", "size=1m,uid=1000"
|
||||
dockerCmd(c, "volume", "create", "-d", "local", name, "--opt", fmt.Sprintf("%s=%s", k1, v1), "--opt", fmt.Sprintf("%s=%s", k2, v2), "--opt", fmt.Sprintf("%s=%s", k3, v3))
|
||||
out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Options }}", name)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k1, v1))
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k2, v2))
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k3, v3))
|
||||
}
|
||||
|
||||
// Test case (1) for 21845: duplicate targets for --volumes-from
|
||||
func (s *DockerSuite) TestDuplicateMountpointsForVolumesFrom(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
image := "vimage"
|
||||
buildImageSuccessfully(c, image, build.WithDockerfile(`
|
||||
FROM busybox
|
||||
VOLUME ["/tmp/data"]`))
|
||||
|
||||
dockerCmd(c, "run", "--name=data1", image, "true")
|
||||
dockerCmd(c, "run", "--name=data2", image, "true")
|
||||
|
||||
out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
|
||||
data1 := strings.TrimSpace(out)
|
||||
c.Assert(data1, checker.Not(checker.Equals), "")
|
||||
|
||||
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
|
||||
data2 := strings.TrimSpace(out)
|
||||
c.Assert(data2, checker.Not(checker.Equals), "")
|
||||
|
||||
// Both volume should exist
|
||||
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, data1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, data2)
|
||||
|
||||
out, _, err := dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-d", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))
|
||||
|
||||
// Only the second volume will be referenced, this is backward compatible
|
||||
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, data2)
|
||||
|
||||
dockerCmd(c, "rm", "-f", "-v", "app")
|
||||
dockerCmd(c, "rm", "-f", "-v", "data1")
|
||||
dockerCmd(c, "rm", "-f", "-v", "data2")
|
||||
|
||||
// Both volume should not exist
|
||||
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
|
||||
}
|
||||
|
||||
// Test case (2) for 21845: duplicate targets for --volumes-from and -v (bind)
|
||||
func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndBind(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
image := "vimage"
|
||||
buildImageSuccessfully(c, image, build.WithDockerfile(`
|
||||
FROM busybox
|
||||
VOLUME ["/tmp/data"]`))
|
||||
|
||||
dockerCmd(c, "run", "--name=data1", image, "true")
|
||||
dockerCmd(c, "run", "--name=data2", image, "true")
|
||||
|
||||
out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
|
||||
data1 := strings.TrimSpace(out)
|
||||
c.Assert(data1, checker.Not(checker.Equals), "")
|
||||
|
||||
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
|
||||
data2 := strings.TrimSpace(out)
|
||||
c.Assert(data2, checker.Not(checker.Equals), "")
|
||||
|
||||
// Both volume should exist
|
||||
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, data1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, data2)
|
||||
|
||||
// /tmp/data is automatically created, because we are not using the modern mount API here
|
||||
out, _, err := dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-v", "/tmp/data:/tmp/data", "-d", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))
|
||||
|
||||
// No volume will be referenced (mount is /tmp/data), this is backward compatible
|
||||
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
|
||||
|
||||
dockerCmd(c, "rm", "-f", "-v", "app")
|
||||
dockerCmd(c, "rm", "-f", "-v", "data1")
|
||||
dockerCmd(c, "rm", "-f", "-v", "data2")
|
||||
|
||||
// Both volume should not exist
|
||||
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
|
||||
}
|
||||
|
||||
// Test case (3) for 21845: duplicate targets for --volumes-from and `Mounts` (API only)
|
||||
func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndMounts(c *check.C) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
image := "vimage"
|
||||
buildImageSuccessfully(c, image, build.WithDockerfile(`
|
||||
FROM busybox
|
||||
VOLUME ["/tmp/data"]`))
|
||||
|
||||
dockerCmd(c, "run", "--name=data1", image, "true")
|
||||
dockerCmd(c, "run", "--name=data2", image, "true")
|
||||
|
||||
out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
|
||||
data1 := strings.TrimSpace(out)
|
||||
c.Assert(data1, checker.Not(checker.Equals), "")
|
||||
|
||||
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
|
||||
data2 := strings.TrimSpace(out)
|
||||
c.Assert(data2, checker.Not(checker.Equals), "")
|
||||
|
||||
// Both volume should exist
|
||||
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, data1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, data2)
|
||||
|
||||
err := os.MkdirAll("/tmp/data", 0755)
|
||||
c.Assert(err, checker.IsNil)
|
||||
// Mounts is available in API
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
config := container.Config{
|
||||
Cmd: []string{"top"},
|
||||
Image: "busybox",
|
||||
}
|
||||
|
||||
hostConfig := container.HostConfig{
|
||||
VolumesFrom: []string{"data1", "data2"},
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: "bind",
|
||||
Source: "/tmp/data",
|
||||
Target: "/tmp/data",
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err = cli.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, "app")
|
||||
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// No volume will be referenced (mount is /tmp/data), this is backward compatible
|
||||
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
|
||||
|
||||
dockerCmd(c, "rm", "-f", "-v", "app")
|
||||
dockerCmd(c, "rm", "-f", "-v", "data1")
|
||||
dockerCmd(c, "rm", "-f", "-v", "data2")
|
||||
|
||||
// Both volume should not exist
|
||||
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
|
||||
}
|
98
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_wait_test.go
generated
vendored
Normal file
98
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_cli_wait_test.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// non-blocking wait with 0 exit code
|
||||
func (s *DockerSuite) TestWaitNonBlockedExitZero(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "true")
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
err := waitInspect(containerID, "{{.State.Running}}", "false", 30*time.Second)
|
||||
c.Assert(err, checker.IsNil) //Container should have stopped by now
|
||||
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "0", check.Commentf("failed to set up container, %v", out))
|
||||
|
||||
}
|
||||
|
||||
// blocking wait with 0 exit code
|
||||
func (s *DockerSuite) TestWaitBlockedExitZero(c *check.C) {
|
||||
// Windows busybox does not support trap in this way, not sleep with sub-second
|
||||
// granularity. It will always exit 0x40010004.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "trap 'exit 0' TERM; while true; do usleep 10; done")
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
c.Assert(waitRun(containerID), checker.IsNil)
|
||||
|
||||
chWait := make(chan string)
|
||||
go func() {
|
||||
chWait <- ""
|
||||
out := icmd.RunCommand(dockerBinary, "wait", containerID).Combined()
|
||||
chWait <- out
|
||||
}()
|
||||
|
||||
<-chWait // make sure the goroutine is started
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
dockerCmd(c, "stop", containerID)
|
||||
|
||||
select {
|
||||
case status := <-chWait:
|
||||
c.Assert(strings.TrimSpace(status), checker.Equals, "0", check.Commentf("expected exit 0, got %s", status))
|
||||
case <-time.After(2 * time.Second):
|
||||
c.Fatal("timeout waiting for `docker wait` to exit")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// non-blocking wait with random exit code
|
||||
func (s *DockerSuite) TestWaitNonBlockedExitRandom(c *check.C) {
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "exit 99")
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
err := waitInspect(containerID, "{{.State.Running}}", "false", 30*time.Second)
|
||||
c.Assert(err, checker.IsNil) //Container should have stopped by now
|
||||
out, _ = dockerCmd(c, "wait", containerID)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "99", check.Commentf("failed to set up container, %v", out))
|
||||
|
||||
}
|
||||
|
||||
// blocking wait with random exit code
|
||||
func (s *DockerSuite) TestWaitBlockedExitRandom(c *check.C) {
|
||||
// Cannot run on Windows as trap in Windows busybox does not support trap in this way.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "trap 'exit 99' TERM; while true; do usleep 10; done")
|
||||
containerID := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(containerID), checker.IsNil)
|
||||
|
||||
chWait := make(chan error)
|
||||
waitCmd := exec.Command(dockerBinary, "wait", containerID)
|
||||
waitCmdOut := bytes.NewBuffer(nil)
|
||||
waitCmd.Stdout = waitCmdOut
|
||||
c.Assert(waitCmd.Start(), checker.IsNil)
|
||||
go func() {
|
||||
chWait <- waitCmd.Wait()
|
||||
}()
|
||||
|
||||
dockerCmd(c, "stop", containerID)
|
||||
|
||||
select {
|
||||
case err := <-chWait:
|
||||
c.Assert(err, checker.IsNil, check.Commentf(waitCmdOut.String()))
|
||||
status, err := waitCmdOut.ReadString('\n')
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(status), checker.Equals, "99", check.Commentf("expected exit 99, got %s", status))
|
||||
case <-time.After(2 * time.Second):
|
||||
waitCmd.Process.Kill()
|
||||
c.Fatal("timeout waiting for `docker wait` to exit")
|
||||
}
|
||||
}
|
250
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_deprecated_api_v124_test.go
generated
vendored
Normal file
250
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_deprecated_api_v124_test.go
generated
vendored
Normal file
|
@ -0,0 +1,250 @@
|
|||
// This file will be removed when we completely drop support for
|
||||
// passing HostConfig to container start API.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func formatV123StartAPIURL(url string) string {
|
||||
return "/v1.23" + url
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestDeprecatedContainerAPIStartHostConfig(c *check.C) {
|
||||
name := "test-deprecated-api-124"
|
||||
dockerCmd(c, "create", "--name", name, "busybox")
|
||||
config := map[string]interface{}{
|
||||
"Binds": []string{"/aa:/bb"},
|
||||
}
|
||||
res, body, err := request.Post("/containers/"+name+"/start", request.JSONBody(config))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest)
|
||||
if versions.GreaterThanOrEqualTo(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
// assertions below won't work before 1.32
|
||||
buf, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest)
|
||||
c.Assert(string(buf), checker.Contains, "was deprecated since API v1.22")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestDeprecatedContainerAPIStartVolumeBinds(c *check.C) {
|
||||
// TODO Windows CI: Investigate further why this fails on Windows to Windows CI.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
path := "/foo"
|
||||
if testEnv.OSType == "windows" {
|
||||
path = `c:\foo`
|
||||
}
|
||||
name := "testing"
|
||||
config := map[string]interface{}{
|
||||
"Image": "busybox",
|
||||
"Volumes": map[string]struct{}{path: {}},
|
||||
}
|
||||
|
||||
res, _, err := request.Post(formatV123StartAPIURL("/containers/create?name="+name), request.JSONBody(config))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusCreated)
|
||||
|
||||
bindPath := RandomTmpDirPath("test", testEnv.OSType)
|
||||
config = map[string]interface{}{
|
||||
"Binds": []string{bindPath + ":" + path},
|
||||
}
|
||||
res, _, err = request.Post(formatV123StartAPIURL("/containers/"+name+"/start"), request.JSONBody(config))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
|
||||
|
||||
pth, err := inspectMountSourceField(name, path)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(pth, checker.Equals, bindPath, check.Commentf("expected volume host path to be %s, got %s", bindPath, pth))
|
||||
}
|
||||
|
||||
// Test for GH#10618
|
||||
func (s *DockerSuite) TestDeprecatedContainerAPIStartDupVolumeBinds(c *check.C) {
|
||||
// TODO Windows to Windows CI - Port this
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "testdups"
|
||||
config := map[string]interface{}{
|
||||
"Image": "busybox",
|
||||
"Volumes": map[string]struct{}{"/tmp": {}},
|
||||
}
|
||||
|
||||
res, _, err := request.Post(formatV123StartAPIURL("/containers/create?name="+name), request.JSONBody(config))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusCreated)
|
||||
|
||||
bindPath1 := RandomTmpDirPath("test1", testEnv.OSType)
|
||||
bindPath2 := RandomTmpDirPath("test2", testEnv.OSType)
|
||||
|
||||
config = map[string]interface{}{
|
||||
"Binds": []string{bindPath1 + ":/tmp", bindPath2 + ":/tmp"},
|
||||
}
|
||||
res, body, err := request.Post(formatV123StartAPIURL("/containers/"+name+"/start"), request.JSONBody(config))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
buf, err := request.ReadBody(body)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest)
|
||||
}
|
||||
c.Assert(string(buf), checker.Contains, "Duplicate mount point", check.Commentf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(buf), err))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestDeprecatedContainerAPIStartVolumesFrom(c *check.C) {
|
||||
// TODO Windows to Windows CI - Port this
|
||||
testRequires(c, DaemonIsLinux)
|
||||
volName := "voltst"
|
||||
volPath := "/tmp"
|
||||
|
||||
dockerCmd(c, "run", "--name", volName, "-v", volPath, "busybox")
|
||||
|
||||
name := "TestContainerAPIStartVolumesFrom"
|
||||
config := map[string]interface{}{
|
||||
"Image": "busybox",
|
||||
"Volumes": map[string]struct{}{volPath: {}},
|
||||
}
|
||||
|
||||
res, _, err := request.Post(formatV123StartAPIURL("/containers/create?name="+name), request.JSONBody(config))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusCreated)
|
||||
|
||||
config = map[string]interface{}{
|
||||
"VolumesFrom": []string{volName},
|
||||
}
|
||||
res, _, err = request.Post(formatV123StartAPIURL("/containers/"+name+"/start"), request.JSONBody(config))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
|
||||
|
||||
pth, err := inspectMountSourceField(name, volPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
pth2, err := inspectMountSourceField(volName, volPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(pth, checker.Equals, pth2, check.Commentf("expected volume host path to be %s, got %s", pth, pth2))
|
||||
}
|
||||
|
||||
// #9981 - Allow a docker created volume (ie, one in /var/lib/docker/volumes) to be used to overwrite (via passing in Binds on api start) an existing volume
|
||||
func (s *DockerSuite) TestDeprecatedPostContainerBindNormalVolume(c *check.C) {
|
||||
// TODO Windows to Windows CI - Port this
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "create", "-v", "/foo", "--name=one", "busybox")
|
||||
|
||||
fooDir, err := inspectMountSourceField("one", "/foo")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "create", "-v", "/foo", "--name=two", "busybox")
|
||||
|
||||
bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}}
|
||||
res, _, err := request.Post(formatV123StartAPIURL("/containers/two/start"), request.JSONBody(bindSpec))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
|
||||
|
||||
fooDir2, err := inspectMountSourceField("two", "/foo")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(fooDir2, checker.Equals, fooDir, check.Commentf("expected volume path to be %s, got: %s", fooDir, fooDir2))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestDeprecatedStartWithTooLowMemoryLimit(c *check.C) {
|
||||
// TODO Windows: Port once memory is supported
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "create", "busybox")
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
config := `{
|
||||
"CpuShares": 100,
|
||||
"Memory": 524287
|
||||
}`
|
||||
|
||||
res, body, err := request.Post(formatV123StartAPIURL("/containers/"+containerID+"/start"), request.RawString(config), request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
b, err2 := request.ReadBody(body)
|
||||
c.Assert(err2, checker.IsNil)
|
||||
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
|
||||
} else {
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest)
|
||||
}
|
||||
c.Assert(string(b), checker.Contains, "Minimum memory limit allowed is 4MB")
|
||||
}
|
||||
|
||||
// #14640
|
||||
func (s *DockerSuite) TestDeprecatedPostContainersStartWithoutLinksInHostConfig(c *check.C) {
|
||||
// TODO Windows: Windows doesn't support supplying a hostconfig on start.
|
||||
// An alternate test could be written to validate the negative testing aspect of this
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "test-host-config-links"
|
||||
dockerCmd(c, append([]string{"create", "--name", name, "busybox"}, sleepCommandForDaemonPlatform()...)...)
|
||||
|
||||
hc := inspectFieldJSON(c, name, "HostConfig")
|
||||
config := `{"HostConfig":` + hc + `}`
|
||||
|
||||
res, b, err := request.Post(formatV123StartAPIURL("/containers/"+name+"/start"), request.RawString(config), request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
|
||||
b.Close()
|
||||
}
|
||||
|
||||
// #14640
|
||||
func (s *DockerSuite) TestDeprecatedPostContainersStartWithLinksInHostConfig(c *check.C) {
|
||||
// TODO Windows: Windows doesn't support supplying a hostconfig on start.
|
||||
// An alternate test could be written to validate the negative testing aspect of this
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "test-host-config-links"
|
||||
dockerCmd(c, "run", "--name", "foo", "-d", "busybox", "top")
|
||||
dockerCmd(c, "create", "--name", name, "--link", "foo:bar", "busybox", "top")
|
||||
|
||||
hc := inspectFieldJSON(c, name, "HostConfig")
|
||||
config := `{"HostConfig":` + hc + `}`
|
||||
|
||||
res, b, err := request.Post(formatV123StartAPIURL("/containers/"+name+"/start"), request.RawString(config), request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
|
||||
b.Close()
|
||||
}
|
||||
|
||||
// #14640
|
||||
func (s *DockerSuite) TestDeprecatedPostContainersStartWithLinksInHostConfigIdLinked(c *check.C) {
|
||||
// Windows does not support links
|
||||
testRequires(c, DaemonIsLinux)
|
||||
name := "test-host-config-links"
|
||||
out, _ := dockerCmd(c, "run", "--name", "link0", "-d", "busybox", "top")
|
||||
defer dockerCmd(c, "stop", "link0")
|
||||
id := strings.TrimSpace(out)
|
||||
dockerCmd(c, "create", "--name", name, "--link", id, "busybox", "top")
|
||||
defer dockerCmd(c, "stop", name)
|
||||
|
||||
hc := inspectFieldJSON(c, name, "HostConfig")
|
||||
config := `{"HostConfig":` + hc + `}`
|
||||
|
||||
res, b, err := request.Post(formatV123StartAPIURL("/containers/"+name+"/start"), request.RawString(config), request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
|
||||
b.Close()
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestDeprecatedStartWithNilDNS(c *check.C) {
|
||||
// TODO Windows: Add once DNS is supported
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "create", "busybox")
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
config := `{"HostConfig": {"Dns": null}}`
|
||||
|
||||
res, b, err := request.Post(formatV123StartAPIURL("/containers/"+containerID+"/start"), request.RawString(config), request.JSON)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
|
||||
b.Close()
|
||||
|
||||
dns := inspectFieldJSON(c, containerID, "HostConfig.Dns")
|
||||
c.Assert(dns, checker.Equals, "[]")
|
||||
}
|
31
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_deprecated_api_v124_unix_test.go
generated
vendored
Normal file
31
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_deprecated_api_v124_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// #19100 This is a deprecated feature test, it should be removed in Docker 1.12
|
||||
func (s *DockerNetworkSuite) TestDeprecatedDockerNetworkStartAPIWithHostconfig(c *check.C) {
|
||||
netName := "test"
|
||||
conName := "foo"
|
||||
dockerCmd(c, "network", "create", netName)
|
||||
dockerCmd(c, "create", "--name", conName, "busybox", "top")
|
||||
|
||||
config := map[string]interface{}{
|
||||
"HostConfig": map[string]interface{}{
|
||||
"NetworkMode": netName,
|
||||
},
|
||||
}
|
||||
_, _, err := request.Post(formatV123StartAPIURL("/containers/"+conName+"/start"), request.JSONBody(config))
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(waitRun(conName), checker.IsNil)
|
||||
networks := inspectField(c, conName, "NetworkSettings.Networks")
|
||||
c.Assert(networks, checker.Contains, netName, check.Commentf(fmt.Sprintf("Should contain '%s' network", netName)))
|
||||
c.Assert(networks, checker.Not(checker.Contains), "bridge", check.Commentf("Should not contain 'bridge' network"))
|
||||
}
|
90
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_hub_pull_suite_test.go
generated
vendored
Normal file
90
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_hub_pull_suite_test.go
generated
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
testdaemon "github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// FIXME. Temporarily turning this off for Windows as GH16039 was breaking
|
||||
// Windows to Linux CI @icecrime
|
||||
if runtime.GOOS != "windows" {
|
||||
check.Suite(newDockerHubPullSuite())
|
||||
}
|
||||
}
|
||||
|
||||
// DockerHubPullSuite provides an isolated daemon that doesn't have all the
|
||||
// images that are baked into our 'global' test environment daemon (e.g.,
|
||||
// busybox, httpserver, ...).
|
||||
//
|
||||
// We use it for push/pull tests where we want to start fresh, and measure the
|
||||
// relative impact of each individual operation. As part of this suite, all
|
||||
// images are removed after each test.
|
||||
type DockerHubPullSuite struct {
|
||||
d *daemon.Daemon
|
||||
ds *DockerSuite
|
||||
}
|
||||
|
||||
// newDockerHubPullSuite returns a new instance of a DockerHubPullSuite.
|
||||
func newDockerHubPullSuite() *DockerHubPullSuite {
|
||||
return &DockerHubPullSuite{
|
||||
ds: &DockerSuite{},
|
||||
}
|
||||
}
|
||||
|
||||
// SetUpSuite starts the suite daemon.
|
||||
func (s *DockerHubPullSuite) SetUpSuite(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
|
||||
s.d.Start(c)
|
||||
}
|
||||
|
||||
// TearDownSuite stops the suite daemon.
|
||||
func (s *DockerHubPullSuite) TearDownSuite(c *check.C) {
|
||||
if s.d != nil {
|
||||
s.d.Stop(c)
|
||||
}
|
||||
}
|
||||
|
||||
// SetUpTest declares that all tests of this suite require network.
|
||||
func (s *DockerHubPullSuite) SetUpTest(c *check.C) {
|
||||
testRequires(c, Network)
|
||||
}
|
||||
|
||||
// TearDownTest removes all images from the suite daemon.
|
||||
func (s *DockerHubPullSuite) TearDownTest(c *check.C) {
|
||||
out := s.Cmd(c, "images", "-aq")
|
||||
images := strings.Split(out, "\n")
|
||||
images = append([]string{"rmi", "-f"}, images...)
|
||||
s.d.Cmd(images...)
|
||||
s.ds.TearDownTest(c)
|
||||
}
|
||||
|
||||
// Cmd executes a command against the suite daemon and returns the combined
|
||||
// output. The function fails the test when the command returns an error.
|
||||
func (s *DockerHubPullSuite) Cmd(c *check.C, name string, arg ...string) string {
|
||||
out, err := s.CmdWithError(name, arg...)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("%q failed with errors: %s, %v", strings.Join(arg, " "), out, err))
|
||||
return out
|
||||
}
|
||||
|
||||
// CmdWithError executes a command against the suite daemon and returns the
|
||||
// combined output as well as any error.
|
||||
func (s *DockerHubPullSuite) CmdWithError(name string, arg ...string) (string, error) {
|
||||
c := s.MakeCmd(name, arg...)
|
||||
b, err := c.CombinedOutput()
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
// MakeCmd returns an exec.Cmd command to run against the suite daemon.
|
||||
func (s *DockerHubPullSuite) MakeCmd(name string, arg ...string) *exec.Cmd {
|
||||
args := []string{"--host", s.d.Sock(), name}
|
||||
args = append(args, arg...)
|
||||
return exec.Command(dockerBinary, args...)
|
||||
}
|
466
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_utils_test.go
generated
vendored
Normal file
466
vendor/github.com/docker/docker-ce/components/engine/integration-cli/docker_utils_test.go
generated
vendored
Normal file
|
@ -0,0 +1,466 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/docker/docker/internal/test/request"
|
||||
"github.com/go-check/check"
|
||||
"gotest.tools/icmd"
|
||||
)
|
||||
|
||||
// Deprecated
|
||||
func daemonHost() string {
|
||||
return request.DaemonHost()
|
||||
}
|
||||
|
||||
func deleteImages(images ...string) error {
|
||||
args := []string{dockerBinary, "rmi", "-f"}
|
||||
return icmd.RunCmd(icmd.Cmd{Command: append(args, images...)}).Error
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Docker or cli.DockerCmd
|
||||
func dockerCmdWithError(args ...string) (string, int, error) {
|
||||
result := cli.Docker(cli.Args(args...))
|
||||
if result.Error != nil {
|
||||
return result.Combined(), result.ExitCode, result.Compare(icmd.Success)
|
||||
}
|
||||
return result.Combined(), result.ExitCode, result.Error
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Docker or cli.DockerCmd
|
||||
func dockerCmd(c *check.C, args ...string) (string, int) {
|
||||
result := cli.DockerCmd(c, args...)
|
||||
return result.Combined(), result.ExitCode
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Docker or cli.DockerCmd
|
||||
func dockerCmdWithResult(args ...string) *icmd.Result {
|
||||
return cli.Docker(cli.Args(args...))
|
||||
}
|
||||
|
||||
func findContainerIP(c *check.C, id string, network string) string {
|
||||
out, _ := dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.IPAddress }}'", network), id)
|
||||
return strings.Trim(out, " \r\n'")
|
||||
}
|
||||
|
||||
func getContainerCount(c *check.C) int {
|
||||
const containers = "Containers:"
|
||||
|
||||
result := icmd.RunCommand(dockerBinary, "info")
|
||||
result.Assert(c, icmd.Success)
|
||||
|
||||
lines := strings.Split(result.Combined(), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, containers) {
|
||||
output := strings.TrimSpace(line)
|
||||
output = strings.TrimLeft(output, containers)
|
||||
output = strings.Trim(output, " ")
|
||||
containerCount, err := strconv.Atoi(output)
|
||||
c.Assert(err, checker.IsNil)
|
||||
return containerCount
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func inspectFieldAndUnmarshall(c *check.C, name, field string, output interface{}) {
|
||||
str := inspectFieldJSON(c, name, field)
|
||||
err := json.Unmarshal([]byte(str), output)
|
||||
if c != nil {
|
||||
c.Assert(err, check.IsNil, check.Commentf("failed to unmarshal: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Inspect
|
||||
func inspectFilter(name, filter string) (string, error) {
|
||||
format := fmt.Sprintf("{{%s}}", filter)
|
||||
result := icmd.RunCommand(dockerBinary, "inspect", "-f", format, name)
|
||||
if result.Error != nil || result.ExitCode != 0 {
|
||||
return "", fmt.Errorf("failed to inspect %s: %s", name, result.Combined())
|
||||
}
|
||||
return strings.TrimSpace(result.Combined()), nil
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Inspect
|
||||
func inspectFieldWithError(name, field string) (string, error) {
|
||||
return inspectFilter(name, fmt.Sprintf(".%s", field))
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Inspect
|
||||
func inspectField(c *check.C, name, field string) string {
|
||||
out, err := inspectFilter(name, fmt.Sprintf(".%s", field))
|
||||
if c != nil {
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Inspect
|
||||
func inspectFieldJSON(c *check.C, name, field string) string {
|
||||
out, err := inspectFilter(name, fmt.Sprintf("json .%s", field))
|
||||
if c != nil {
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Inspect
|
||||
func inspectFieldMap(c *check.C, name, path, field string) string {
|
||||
out, err := inspectFilter(name, fmt.Sprintf("index .%s %q", path, field))
|
||||
if c != nil {
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Inspect
|
||||
func inspectMountSourceField(name, destination string) (string, error) {
|
||||
m, err := inspectMountPoint(name, destination)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return m.Source, nil
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Inspect
|
||||
func inspectMountPoint(name, destination string) (types.MountPoint, error) {
|
||||
out, err := inspectFilter(name, "json .Mounts")
|
||||
if err != nil {
|
||||
return types.MountPoint{}, err
|
||||
}
|
||||
|
||||
return inspectMountPointJSON(out, destination)
|
||||
}
|
||||
|
||||
var errMountNotFound = errors.New("mount point not found")
|
||||
|
||||
// Deprecated: use cli.Inspect
|
||||
func inspectMountPointJSON(j, destination string) (types.MountPoint, error) {
|
||||
var mp []types.MountPoint
|
||||
if err := json.Unmarshal([]byte(j), &mp); err != nil {
|
||||
return types.MountPoint{}, err
|
||||
}
|
||||
|
||||
var m *types.MountPoint
|
||||
for _, c := range mp {
|
||||
if c.Destination == destination {
|
||||
m = &c
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if m == nil {
|
||||
return types.MountPoint{}, errMountNotFound
|
||||
}
|
||||
|
||||
return *m, nil
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Inspect
|
||||
func inspectImage(c *check.C, name, filter string) string {
|
||||
args := []string{"inspect", "--type", "image"}
|
||||
if filter != "" {
|
||||
format := fmt.Sprintf("{{%s}}", filter)
|
||||
args = append(args, "-f", format)
|
||||
}
|
||||
args = append(args, name)
|
||||
result := icmd.RunCommand(dockerBinary, args...)
|
||||
result.Assert(c, icmd.Success)
|
||||
return strings.TrimSpace(result.Combined())
|
||||
}
|
||||
|
||||
func getIDByName(c *check.C, name string) string {
|
||||
id, err := inspectFieldWithError(name, "Id")
|
||||
c.Assert(err, checker.IsNil)
|
||||
return id
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Build
|
||||
func buildImageSuccessfully(c *check.C, name string, cmdOperators ...cli.CmdOperator) {
|
||||
buildImage(name, cmdOperators...).Assert(c, icmd.Success)
|
||||
}
|
||||
|
||||
// Deprecated: use cli.Build
|
||||
func buildImage(name string, cmdOperators ...cli.CmdOperator) *icmd.Result {
|
||||
return cli.Docker(cli.Build(name), cmdOperators...)
|
||||
}
|
||||
|
||||
// Write `content` to the file at path `dst`, creating it if necessary,
|
||||
// as well as any missing directories.
|
||||
// The file is truncated if it already exists.
|
||||
// Fail the test when error occurs.
|
||||
func writeFile(dst, content string, c *check.C) {
|
||||
// Create subdirectories if necessary
|
||||
c.Assert(os.MkdirAll(path.Dir(dst), 0700), check.IsNil)
|
||||
f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
|
||||
c.Assert(err, check.IsNil)
|
||||
defer f.Close()
|
||||
// Write content (truncate if it exists)
|
||||
_, err = io.Copy(f, strings.NewReader(content))
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
// Return the contents of file at path `src`.
|
||||
// Fail the test when error occurs.
|
||||
func readFile(src string, c *check.C) (content string) {
|
||||
data, err := ioutil.ReadFile(src)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func containerStorageFile(containerID, basename string) string {
|
||||
return filepath.Join(testEnv.PlatformDefaults.ContainerStoragePath, containerID, basename)
|
||||
}
|
||||
|
||||
// docker commands that use this function must be run with the '-d' switch.
|
||||
func runCommandAndReadContainerFile(c *check.C, filename string, command string, args ...string) []byte {
|
||||
result := icmd.RunCommand(command, args...)
|
||||
result.Assert(c, icmd.Success)
|
||||
contID := strings.TrimSpace(result.Combined())
|
||||
if err := waitRun(contID); err != nil {
|
||||
c.Fatalf("%v: %q", contID, err)
|
||||
}
|
||||
return readContainerFile(c, contID, filename)
|
||||
}
|
||||
|
||||
func readContainerFile(c *check.C, containerID, filename string) []byte {
|
||||
f, err := os.Open(containerStorageFile(containerID, filename))
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer f.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(f)
|
||||
c.Assert(err, checker.IsNil)
|
||||
return content
|
||||
}
|
||||
|
||||
func readContainerFileWithExec(c *check.C, containerID, filename string) []byte {
|
||||
result := icmd.RunCommand(dockerBinary, "exec", containerID, "cat", filename)
|
||||
result.Assert(c, icmd.Success)
|
||||
return []byte(result.Combined())
|
||||
}
|
||||
|
||||
// daemonTime provides the current time on the daemon host
|
||||
func daemonTime(c *check.C) time.Time {
|
||||
if testEnv.IsLocalDaemon() {
|
||||
return time.Now()
|
||||
}
|
||||
cli, err := client.NewEnvClient()
|
||||
c.Assert(err, check.IsNil)
|
||||
defer cli.Close()
|
||||
|
||||
info, err := cli.Info(context.Background())
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
|
||||
c.Assert(err, check.IsNil, check.Commentf("invalid time format in GET /info response"))
|
||||
return dt
|
||||
}
|
||||
|
||||
// daemonUnixTime returns the current time on the daemon host with nanoseconds precision.
|
||||
// It return the time formatted how the client sends timestamps to the server.
|
||||
func daemonUnixTime(c *check.C) string {
|
||||
return parseEventTime(daemonTime(c))
|
||||
}
|
||||
|
||||
func parseEventTime(t time.Time) string {
|
||||
return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond()))
|
||||
}
|
||||
|
||||
// appendBaseEnv appends the minimum set of environment variables to exec the
|
||||
// docker cli binary for testing with correct configuration to the given env
|
||||
// list.
|
||||
func appendBaseEnv(isTLS bool, env ...string) []string {
|
||||
preserveList := []string{
|
||||
// preserve remote test host
|
||||
"DOCKER_HOST",
|
||||
|
||||
// windows: requires preserving SystemRoot, otherwise dial tcp fails
|
||||
// with "GetAddrInfoW: A non-recoverable error occurred during a database lookup."
|
||||
"SystemRoot",
|
||||
|
||||
// testing help text requires the $PATH to dockerd is set
|
||||
"PATH",
|
||||
}
|
||||
if isTLS {
|
||||
preserveList = append(preserveList, "DOCKER_TLS_VERIFY", "DOCKER_CERT_PATH")
|
||||
}
|
||||
|
||||
for _, key := range preserveList {
|
||||
if val := os.Getenv(key); val != "" {
|
||||
env = append(env, fmt.Sprintf("%s=%s", key, val))
|
||||
}
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
func createTmpFile(c *check.C, content string) string {
|
||||
f, err := ioutil.TempFile("", "testfile")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
filename := f.Name()
|
||||
|
||||
err = ioutil.WriteFile(filename, []byte(content), 0644)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
return filename
|
||||
}
|
||||
|
||||
// waitRun will wait for the specified container to be running, maximum 5 seconds.
|
||||
// Deprecated: use cli.WaitFor
|
||||
func waitRun(contID string) error {
|
||||
return waitInspect(contID, "{{.State.Running}}", "true", 5*time.Second)
|
||||
}
|
||||
|
||||
// waitInspect will wait for the specified container to have the specified string
|
||||
// in the inspect output. It will wait until the specified timeout (in seconds)
|
||||
// is reached.
|
||||
// Deprecated: use cli.WaitFor
|
||||
func waitInspect(name, expr, expected string, timeout time.Duration) error {
|
||||
return waitInspectWithArgs(name, expr, expected, timeout)
|
||||
}
|
||||
|
||||
// Deprecated: use cli.WaitFor
|
||||
func waitInspectWithArgs(name, expr, expected string, timeout time.Duration, arg ...string) error {
|
||||
return daemon.WaitInspectWithArgs(dockerBinary, name, expr, expected, timeout, arg...)
|
||||
}
|
||||
|
||||
func getInspectBody(c *check.C, version, id string) []byte {
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion(version))
|
||||
c.Assert(err, check.IsNil)
|
||||
defer cli.Close()
|
||||
_, body, err := cli.ContainerInspectWithRaw(context.Background(), id, false)
|
||||
c.Assert(err, check.IsNil)
|
||||
return body
|
||||
}
|
||||
|
||||
// Run a long running idle task in a background container using the
|
||||
// system-specific default image and command.
|
||||
func runSleepingContainer(c *check.C, extraArgs ...string) string {
|
||||
return runSleepingContainerInImage(c, defaultSleepImage, extraArgs...)
|
||||
}
|
||||
|
||||
// Run a long running idle task in a background container using the specified
|
||||
// image and the system-specific command.
|
||||
func runSleepingContainerInImage(c *check.C, image string, extraArgs ...string) string {
|
||||
args := []string{"run", "-d"}
|
||||
args = append(args, extraArgs...)
|
||||
args = append(args, image)
|
||||
args = append(args, sleepCommandForDaemonPlatform()...)
|
||||
return strings.TrimSpace(cli.DockerCmd(c, args...).Combined())
|
||||
}
|
||||
|
||||
// minimalBaseImage returns the name of the minimal base image for the current
|
||||
// daemon platform.
|
||||
func minimalBaseImage() string {
|
||||
return testEnv.PlatformDefaults.BaseImage
|
||||
}
|
||||
|
||||
func getGoroutineNumber() (int, error) {
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
info, err := cli.Info(context.Background())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return info.NGoroutines, nil
|
||||
}
|
||||
|
||||
func waitForGoroutines(expected int) error {
|
||||
t := time.After(30 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-t:
|
||||
n, err := getGoroutineNumber()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n > expected {
|
||||
return fmt.Errorf("leaked goroutines: expected less than or equal to %d, got: %d", expected, n)
|
||||
}
|
||||
default:
|
||||
n, err := getGoroutineNumber()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n <= expected {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getErrorMessage returns the error message from an error API response
|
||||
func getErrorMessage(c *check.C, body []byte) string {
|
||||
var resp types.ErrorResponse
|
||||
c.Assert(json.Unmarshal(body, &resp), check.IsNil)
|
||||
return strings.TrimSpace(resp.Message)
|
||||
}
|
||||
|
||||
func waitAndAssert(c *check.C, timeout time.Duration, f checkF, checker check.Checker, args ...interface{}) {
|
||||
after := time.After(timeout)
|
||||
for {
|
||||
v, comment := f(c)
|
||||
assert, _ := checker.Check(append([]interface{}{v}, args...), checker.Info().Params)
|
||||
select {
|
||||
case <-after:
|
||||
assert = true
|
||||
default:
|
||||
}
|
||||
if assert {
|
||||
if comment != nil {
|
||||
args = append(args, comment)
|
||||
}
|
||||
c.Assert(v, checker, args...)
|
||||
return
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
type checkF func(*check.C) (interface{}, check.CommentInterface)
|
||||
type reducer func(...interface{}) interface{}
|
||||
|
||||
func reducedCheck(r reducer, funcs ...checkF) checkF {
|
||||
return func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
var values []interface{}
|
||||
var comments []string
|
||||
for _, f := range funcs {
|
||||
v, comment := f(c)
|
||||
values = append(values, v)
|
||||
if comment != nil {
|
||||
comments = append(comments, comment.CheckCommentString())
|
||||
}
|
||||
}
|
||||
return r(values...), check.Commentf("%v", strings.Join(comments, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
func sumAsIntegers(vals ...interface{}) interface{} {
|
||||
var s int
|
||||
for _, v := range vals {
|
||||
s += v.(int)
|
||||
}
|
||||
return s
|
||||
}
|
49
vendor/github.com/docker/docker-ce/components/engine/integration-cli/environment/environment.go
generated
vendored
Normal file
49
vendor/github.com/docker/docker-ce/components/engine/integration-cli/environment/environment.go
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
package environment // import "github.com/docker/docker/integration-cli/environment"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/docker/docker/internal/test/environment"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultClientBinary is the name of the docker binary
|
||||
DefaultClientBinary = os.Getenv("TEST_CLIENT_BINARY")
|
||||
)
|
||||
|
||||
func init() {
|
||||
if DefaultClientBinary == "" {
|
||||
DefaultClientBinary = "docker"
|
||||
}
|
||||
}
|
||||
|
||||
// Execution contains information about the current test execution and daemon
|
||||
// under test
|
||||
type Execution struct {
|
||||
environment.Execution
|
||||
dockerBinary string
|
||||
}
|
||||
|
||||
// DockerBinary returns the docker binary for this testing environment
|
||||
func (e *Execution) DockerBinary() string {
|
||||
return e.dockerBinary
|
||||
}
|
||||
|
||||
// New returns details about the testing environment
|
||||
func New() (*Execution, error) {
|
||||
env, err := environment.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dockerBinary, err := exec.LookPath(DefaultClientBinary)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Execution{
|
||||
Execution: *env,
|
||||
dockerBinary: dockerBinary,
|
||||
}, nil
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue