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

This commit is contained in:
GordonTheTurtle
2018-02-13 17:04:05 +00:00
17 changed files with 467 additions and 482 deletions
+13 -2
View File
@@ -6173,8 +6173,19 @@ paths:
type: "integer"
- name: "buildargs"
in: "query"
description: "JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg)"
type: "integer"
description: >
JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker
uses the buildargs as the environment context for commands run via the `Dockerfile` RUN
instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for
passing secret values.
For example, the build arg `FOO=bar` would become `{"FOO":"bar"}` in JSON. This would result in the
the query parameter `buildargs={"FOO":"bar"}`. Note that `{"FOO":"bar"}` should be URI component encoded.
[Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg)
type: "string"
- name: "shmsize"
in: "query"
description: "Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB."
+14 -15
View File
@@ -133,23 +133,15 @@ func FromEnv(c *Client) error {
},
CheckRedirect: CheckRedirect,
}
WithHTTPClient(httpClient)(c)
}
host := os.Getenv("DOCKER_HOST")
if host != "" {
var err error
// WithHost will create an API client if it doesn't exist
if err := WithHost(host)(c); err != nil {
return err
}
httpClient, err = defaultHTTPClient(host)
if err != nil {
return err
}
}
if httpClient != nil {
if err := WithHTTPClient(httpClient)(c); err != nil {
return err
}
}
version := os.Getenv("DOCKER_API_VERSION")
if version != "" {
@@ -167,7 +159,8 @@ func WithVersion(version string) func(*Client) error {
}
}
// WithHost overrides the client host with the specified one
// WithHost overrides the client host with the specified one, creating a new
// http client if one doesn't exist
func WithHost(host string) func(*Client) error {
return func(c *Client) error {
hostURL, err := ParseHostURL(host)
@@ -178,11 +171,17 @@ func WithHost(host string) func(*Client) error {
c.proto = hostURL.Scheme
c.addr = hostURL.Host
c.basePath = hostURL.Path
client, err := defaultHTTPClient(host)
if err != nil {
return err
if c.client == nil {
client, err := defaultHTTPClient(host)
if err != nil {
return err
}
return WithHTTPClient(client)(c)
}
return WithHTTPClient(client)(c)
if transport, ok := c.client.Transport.(*http.Transport); ok {
return sockets.ConfigureTransport(transport, c.proto, c.addr)
}
return fmt.Errorf("cannot apply host to http transport")
}
}
@@ -16,7 +16,7 @@ import (
)
func (s *DockerSuite) TestContainersAPICreateMountsBindNamedPipe(c *check.C) {
testRequires(c, SameHostDaemon, DaemonIsWindowsAtLeastBuild(16210)) // Named pipe support was added in RS3
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())
@@ -1,123 +0,0 @@
// +build !windows
package main
import (
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/integration-cli/checker"
"github.com/go-check/check"
"golang.org/x/net/context"
)
func (s *DockerSwarmSuite) TestAPISwarmConfigsEmptyList(c *check.C) {
d := s.AddDaemon(c, true, true)
configs := d.ListConfigs(c)
c.Assert(configs, checker.NotNil)
c.Assert(len(configs), checker.Equals, 0, check.Commentf("configs: %#v", configs))
}
func (s *DockerSwarmSuite) TestAPISwarmConfigsCreate(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))
configs := d.ListConfigs(c)
c.Assert(len(configs), checker.Equals, 1, check.Commentf("configs: %#v", configs))
name := configs[0].Spec.Annotations.Name
c.Assert(name, checker.Equals, testName, check.Commentf("configs: %s", name))
}
func (s *DockerSwarmSuite) TestAPISwarmConfigsDelete(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))
config := d.GetConfig(c, id)
c.Assert(config.ID, checker.Equals, id, check.Commentf("config: %v", config))
d.DeleteConfig(c, config.ID)
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
_, _, err = cli.ConfigInspectWithRaw(context.Background(), id)
c.Assert(err.Error(), checker.Contains, "No such config")
}
func (s *DockerSwarmSuite) TestAPISwarmConfigsUpdate(c *check.C) {
d := s.AddDaemon(c, true, true)
testName := "test_config"
id := d.CreateConfig(c, swarm.ConfigSpec{
Annotations: swarm.Annotations{
Name: testName,
Labels: map[string]string{
"test": "test1",
},
},
Data: []byte("TESTINGDATA"),
})
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
config := d.GetConfig(c, id)
c.Assert(config.ID, checker.Equals, id, check.Commentf("config: %v", config))
// test UpdateConfig with full ID
d.UpdateConfig(c, id, func(s *swarm.Config) {
s.Spec.Labels = map[string]string{
"test": "test1",
}
})
config = d.GetConfig(c, id)
c.Assert(config.Spec.Labels["test"], checker.Equals, "test1", check.Commentf("config: %v", config))
// test UpdateConfig with full name
d.UpdateConfig(c, config.Spec.Name, func(s *swarm.Config) {
s.Spec.Labels = map[string]string{
"test": "test2",
}
})
config = d.GetConfig(c, id)
c.Assert(config.Spec.Labels["test"], checker.Equals, "test2", check.Commentf("config: %v", config))
// test UpdateConfig with prefix ID
d.UpdateConfig(c, id[:1], func(s *swarm.Config) {
s.Spec.Labels = map[string]string{
"test": "test3",
}
})
config = d.GetConfig(c, id)
c.Assert(config.Spec.Labels["test"], checker.Equals, "test3", check.Commentf("config: %v", config))
// test UpdateConfig in updating Data which is not supported in daemon
// this test will produce an error in func UpdateConfig
config = d.GetConfig(c, id)
config.Spec.Data = []byte("TESTINGDATA2")
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
expected := "only updates to Labels are allowed"
err = cli.ConfigUpdate(context.Background(), config.ID, config.Version, config.Spec)
c.Assert(err.Error(), checker.Contains, expected)
}
@@ -1,136 +0,0 @@
// +build !windows
package main
import (
"net/http"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/integration-cli/checker"
"github.com/go-check/check"
"golang.org/x/net/context"
)
func (s *DockerSwarmSuite) TestAPISwarmSecretsEmptyList(c *check.C) {
d := s.AddDaemon(c, true, true)
secrets := d.ListSecrets(c)
c.Assert(secrets, checker.NotNil)
c.Assert(len(secrets), checker.Equals, 0, check.Commentf("secrets: %#v", secrets))
}
func (s *DockerSwarmSuite) TestAPISwarmSecretsCreate(c *check.C) {
d := s.AddDaemon(c, true, true)
testName := "test_secret"
secretSpec := swarm.SecretSpec{
Annotations: swarm.Annotations{
Name: testName,
},
Data: []byte("TESTINGDATA"),
}
id := d.CreateSecret(c, secretSpec)
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
secrets := d.ListSecrets(c)
c.Assert(len(secrets), checker.Equals, 1, check.Commentf("secrets: %#v", secrets))
name := secrets[0].Spec.Annotations.Name
c.Assert(name, checker.Equals, testName, check.Commentf("secret: %s", name))
// create an already existing secret, daemon should return a status code of 409
status, out, err := d.SockRequest("POST", "/secrets/create", secretSpec)
c.Assert(err, checker.IsNil)
c.Assert(status, checker.Equals, http.StatusConflict, check.Commentf("secret create: %s", string(out)))
}
func (s *DockerSwarmSuite) TestAPISwarmSecretsDelete(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))
secret := d.GetSecret(c, id)
c.Assert(secret.ID, checker.Equals, id, check.Commentf("secret: %v", secret))
d.DeleteSecret(c, secret.ID)
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
_, _, err = cli.SecretInspectWithRaw(context.Background(), id)
c.Assert(err.Error(), checker.Contains, "No such secret")
id = "non-existing"
err = cli.SecretRemove(context.Background(), id)
c.Assert(err.Error(), checker.Contains, "No such secret: non-existing")
}
func (s *DockerSwarmSuite) TestAPISwarmSecretsUpdate(c *check.C) {
d := s.AddDaemon(c, true, true)
testName := "test_secret"
id := d.CreateSecret(c, swarm.SecretSpec{
Annotations: swarm.Annotations{
Name: testName,
Labels: map[string]string{
"test": "test1",
},
},
Data: []byte("TESTINGDATA"),
})
c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
secret := d.GetSecret(c, id)
c.Assert(secret.ID, checker.Equals, id, check.Commentf("secret: %v", secret))
// test UpdateSecret with full ID
d.UpdateSecret(c, id, func(s *swarm.Secret) {
s.Spec.Labels = map[string]string{
"test": "test1",
}
})
secret = d.GetSecret(c, id)
c.Assert(secret.Spec.Labels["test"], checker.Equals, "test1", check.Commentf("secret: %v", secret))
// test UpdateSecret with full name
d.UpdateSecret(c, secret.Spec.Name, func(s *swarm.Secret) {
s.Spec.Labels = map[string]string{
"test": "test2",
}
})
secret = d.GetSecret(c, id)
c.Assert(secret.Spec.Labels["test"], checker.Equals, "test2", check.Commentf("secret: %v", secret))
// test UpdateSecret with prefix ID
d.UpdateSecret(c, id[:1], func(s *swarm.Secret) {
s.Spec.Labels = map[string]string{
"test": "test3",
}
})
secret = d.GetSecret(c, id)
c.Assert(secret.Spec.Labels["test"], checker.Equals, "test3", check.Commentf("secret: %v", secret))
// test UpdateSecret in updating Data which is not supported in daemon
// this test will produce an error in func UpdateSecret
secret = d.GetSecret(c, id)
secret.Spec.Data = []byte("TESTINGDATA2")
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
expected := "only updates to Labels are allowed"
err = cli.SecretUpdate(context.Background(), secret.ID, secret.Version, secret.Spec)
c.Assert(err.Error(), checker.Contains, expected)
}
@@ -1,126 +0,0 @@
// +build !windows
package main
import (
"strings"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/integration-cli/checker"
"github.com/go-check/check"
)
func (s *DockerSwarmSuite) TestConfigList(c *check.C) {
testRequires(c, SameHostDaemon)
d := s.AddDaemon(c, true, true)
testName0 := "test0"
testName1 := "test1"
// create config test0
id0 := d.CreateConfig(c, swarm.ConfigSpec{
Annotations: swarm.Annotations{
Name: testName0,
Labels: map[string]string{"type": "test"},
},
Data: []byte("TESTINGDATA0"),
})
c.Assert(id0, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id0))
config := d.GetConfig(c, id0)
c.Assert(config.Spec.Name, checker.Equals, testName0)
// create config test1
id1 := d.CreateConfig(c, swarm.ConfigSpec{
Annotations: swarm.Annotations{
Name: testName1,
Labels: map[string]string{"type": "production"},
},
Data: []byte("TESTINGDATA1"),
})
c.Assert(id1, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id1))
config = d.GetConfig(c, id1)
c.Assert(config.Spec.Name, checker.Equals, testName1)
// test by command `docker config ls`
out, err := d.Cmd("config", "ls")
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Contains, testName0)
c.Assert(strings.TrimSpace(out), checker.Contains, testName1)
// test filter by name `docker config ls --filter name=xxx`
args := []string{
"config",
"ls",
"--filter",
"name=test0",
}
out, err = d.Cmd(args...)
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Contains, testName0)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName1)
// test filter by id `docker config ls --filter id=xxx`
args = []string{
"config",
"ls",
"--filter",
"id=" + id1,
}
out, err = d.Cmd(args...)
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName0)
c.Assert(strings.TrimSpace(out), checker.Contains, testName1)
// test filter by label `docker config ls --filter label=xxx`
args = []string{
"config",
"ls",
"--filter",
"label=type",
}
out, err = d.Cmd(args...)
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Contains, testName0)
c.Assert(strings.TrimSpace(out), checker.Contains, testName1)
args = []string{
"config",
"ls",
"--filter",
"label=type=test",
}
out, err = d.Cmd(args...)
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Contains, testName0)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName1)
args = []string{
"config",
"ls",
"--filter",
"label=type=production",
}
out, err = d.Cmd(args...)
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName0)
c.Assert(strings.TrimSpace(out), checker.Contains, testName1)
// test invalid filter `docker config ls --filter noexisttype=xxx`
args = []string{
"config",
"ls",
"--filter",
"noexisttype=test0",
}
out, err = d.Cmd(args...)
c.Assert(err, checker.NotNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Contains, "Error response from daemon: Invalid filter 'noexisttype'")
}
@@ -1,30 +0,0 @@
// +build !windows
package main
import (
"github.com/docker/docker/integration-cli/checker"
"github.com/go-check/check"
)
func (s *DockerSuite) TestInspectOomKilledTrue(c *check.C) {
testRequires(c, DaemonIsLinux, memoryLimitSupport, swapMemorySupport)
name := "testoomkilled"
_, exitCode, _ := dockerCmdWithError("run", "--name", name, "--memory", "32MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done")
c.Assert(exitCode, checker.Equals, 137, check.Commentf("OOM exit should be 137"))
oomKilled := inspectField(c, name, "State.OOMKilled")
c.Assert(oomKilled, checker.Equals, "true")
}
func (s *DockerSuite) TestInspectOomKilledFalse(c *check.C) {
testRequires(c, DaemonIsLinux, memoryLimitSupport, swapMemorySupport)
name := "testoomkilled"
dockerCmd(c, "run", "--name", name, "--memory", "32MB", "busybox", "sh", "-c", "echo hello world")
oomKilled := inspectField(c, name, "State.OOMKilled")
c.Assert(oomKilled, checker.Equals, "false")
}
@@ -4002,7 +4002,7 @@ func (s *DockerSuite) TestRunAttachFailedNoLeak(c *check.C) {
v, err := kernel.GetKernelVersion()
c.Assert(err, checker.IsNil)
build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0])
if build >= 16292 { // @jhowardmsft TODO - replace with final RS3 build and ==
if build == 16299 {
c.Skip("Temporarily disabled on RS3 builds")
}
}
@@ -1,43 +0,0 @@
package main
import (
"strings"
"time"
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/integration-cli/cli"
"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/icmd"
)
func (s *DockerSuite) TestUpdateRestartPolicy(c *check.C) {
out := cli.DockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "sh", "-c", "sleep 1 && false").Combined()
timeout := 60 * time.Second
if testEnv.OSType == "windows" {
timeout = 180 * time.Second
}
id := strings.TrimSpace(string(out))
// update restart policy to on-failure:5
cli.DockerCmd(c, "update", "--restart=on-failure:5", id)
cli.WaitExited(c, id, timeout)
count := inspectField(c, id, "RestartCount")
c.Assert(count, checker.Equals, "5")
maximumRetryCount := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount")
c.Assert(maximumRetryCount, checker.Equals, "5")
}
func (s *DockerSuite) TestUpdateRestartWithAutoRemoveFlag(c *check.C) {
out := runSleepingContainer(c, "--rm")
id := strings.TrimSpace(out)
// update restart policy for an AutoRemove container
cli.Docker(cli.Args("update", "--restart=always", id)).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "Restart policy cannot be updated because AutoRemove is enabled for the container",
})
}
@@ -0,0 +1,190 @@
package config
import (
"sort"
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
swarmtypes "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/docker/docker/integration/internal/swarm"
"github.com/docker/docker/internal/testutil"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)
func TestConfigList(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
require.NoError(t, err)
ctx := context.Background()
// This test case is ported from the original TestConfigsEmptyList
configs, err := client.ConfigList(ctx, types.ConfigListOptions{})
require.NoError(t, err)
assert.Equal(t, len(configs), 0)
testName0 := "test0"
testName1 := "test1"
testNames := []string{testName0, testName1}
sort.Strings(testNames)
// create config test0
createConfig(ctx, t, client, testName0, []byte("TESTINGDATA0"), map[string]string{"type": "test"})
config1ID := createConfig(ctx, t, client, testName1, []byte("TESTINGDATA1"), map[string]string{"type": "production"})
names := func(entries []swarmtypes.Config) []string {
values := []string{}
for _, entry := range entries {
values = append(values, entry.Spec.Name)
}
sort.Strings(values)
return values
}
// test by `config ls`
entries, err := client.ConfigList(ctx, types.ConfigListOptions{})
require.NoError(t, err)
assert.Equal(t, names(entries), testNames)
testCases := []struct {
filters filters.Args
expected []string
}{
// test filter by name `config ls --filter name=xxx`
{
filters: filters.NewArgs(filters.Arg("name", testName0)),
expected: []string{testName0},
},
// test filter by id `config ls --filter id=xxx`
{
filters: filters.NewArgs(filters.Arg("id", config1ID)),
expected: []string{testName1},
},
// test filter by label `config ls --filter label=xxx`
{
filters: filters.NewArgs(filters.Arg("label", "type")),
expected: testNames,
},
{
filters: filters.NewArgs(filters.Arg("label", "type=test")),
expected: []string{testName0},
},
{
filters: filters.NewArgs(filters.Arg("label", "type=production")),
expected: []string{testName1},
},
}
for _, tc := range testCases {
entries, err = client.ConfigList(ctx, types.ConfigListOptions{
Filters: tc.filters,
})
require.NoError(t, err)
assert.Equal(t, names(entries), tc.expected)
}
}
func createConfig(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string {
config, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{
Annotations: swarmtypes.Annotations{
Name: name,
Labels: labels,
},
Data: data,
})
require.NoError(t, err)
assert.NotEqual(t, config.ID, "")
return config.ID
}
func TestConfigsCreateAndDelete(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
require.NoError(t, err)
ctx := context.Background()
testName := "test_config"
// This test case is ported from the original TestConfigsCreate
configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
insp, _, err := client.ConfigInspectWithRaw(ctx, configID)
require.NoError(t, err)
assert.Equal(t, insp.Spec.Name, testName)
// This test case is ported from the original TestConfigsDelete
err = client.ConfigRemove(ctx, configID)
require.NoError(t, err)
insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
testutil.ErrorContains(t, err, "No such config")
}
func TestConfigsUpdate(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
require.NoError(t, err)
ctx := context.Background()
testName := "test_config"
// This test case is ported from the original TestConfigsCreate
configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
insp, _, err := client.ConfigInspectWithRaw(ctx, configID)
require.NoError(t, err)
assert.Equal(t, insp.ID, configID)
// test UpdateConfig with full ID
insp.Spec.Labels = map[string]string{"test": "test1"}
err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec)
require.NoError(t, err)
insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
require.NoError(t, err)
assert.Equal(t, insp.Spec.Labels["test"], "test1")
// test UpdateConfig with full name
insp.Spec.Labels = map[string]string{"test": "test2"}
err = client.ConfigUpdate(ctx, testName, insp.Version, insp.Spec)
require.NoError(t, err)
insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
require.NoError(t, err)
assert.Equal(t, insp.Spec.Labels["test"], "test2")
// test UpdateConfig with prefix ID
insp.Spec.Labels = map[string]string{"test": "test3"}
err = client.ConfigUpdate(ctx, configID[:1], insp.Version, insp.Spec)
require.NoError(t, err)
insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
require.NoError(t, err)
assert.Equal(t, insp.Spec.Labels["test"], "test3")
// test UpdateConfig in updating Data which is not supported in daemon
// this test will produce an error in func UpdateConfig
insp.Spec.Data = []byte("TESTINGDATA2")
err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec)
testutil.ErrorContains(t, err, "only updates to Labels are allowed")
}
@@ -0,0 +1,33 @@
package config
import (
"fmt"
"os"
"testing"
"github.com/docker/docker/internal/test/environment"
)
var testEnv *environment.Execution
func TestMain(m *testing.M) {
var err error
testEnv, err = environment.New()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = environment.EnsureFrozenImagesLinux(testEnv)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
testEnv.Print()
os.Exit(m.Run())
}
func setupTest(t *testing.T) func() {
environment.ProtectAll(t, testEnv)
return func() { testEnv.Clean(t) }
}
@@ -11,6 +11,7 @@ import (
"github.com/docker/docker/integration/internal/request"
"github.com/gotestyourself/gotestyourself/poll"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -146,3 +147,39 @@ func TestKillDifferentUserContainer(t *testing.T) {
require.NoError(t, err)
poll.WaitOn(t, containerIsInState(ctx, client, id, "exited"), poll.WithDelay(100*time.Millisecond))
}
func TestInspectOomKilledTrue(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || !testEnv.DaemonInfo.MemoryLimit || !testEnv.DaemonInfo.SwapLimit)
defer setupTest(t)()
ctx := context.Background()
client := request.NewAPIClient(t)
name := "testoomkilled"
cID := container.Run(t, ctx, client, container.WithName(name), container.WithCmd("sh", "-c", "x=a; while true; do x=$x$x$x$x; done"), func(c *container.TestContainerConfig) {
c.HostConfig.Resources.Memory = 32 * 1024 * 1024
})
poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
inspect, err := client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.State.OOMKilled, true)
}
func TestInspectOomKilledFalse(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux" || !testEnv.DaemonInfo.MemoryLimit || !testEnv.DaemonInfo.SwapLimit)
defer setupTest(t)()
ctx := context.Background()
client := request.NewAPIClient(t)
name := "testoomkilled"
cID := container.Run(t, ctx, client, container.WithName(name), container.WithCmd("sh", "-c", "echo hello world"))
poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond))
inspect, err := client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.State.OOMKilled, false)
}
@@ -0,0 +1,65 @@
package container // import "github.com/docker/docker/integration/container"
import (
"context"
"testing"
"time"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/integration/internal/container"
"github.com/docker/docker/integration/internal/request"
"github.com/docker/docker/internal/testutil"
"github.com/gotestyourself/gotestyourself/poll"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestUpdateRestartPolicy(t *testing.T) {
defer setupTest(t)()
client := request.NewAPIClient(t)
ctx := context.Background()
cID := container.Run(t, ctx, client, container.WithCmd("sh", "-c", "sleep 1 && false"), func(c *container.TestContainerConfig) {
c.HostConfig.RestartPolicy = containertypes.RestartPolicy{
Name: "on-failure",
MaximumRetryCount: 3,
}
})
_, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
RestartPolicy: containertypes.RestartPolicy{
Name: "on-failure",
MaximumRetryCount: 5,
},
})
require.NoError(t, err)
timeout := 60 * time.Second
if testEnv.OSType == "windows" {
timeout = 180 * time.Second
}
poll.WaitOn(t, containerIsInState(ctx, client, cID, "exited"), poll.WithDelay(100*time.Millisecond), poll.WithTimeout(timeout))
inspect, err := client.ContainerInspect(ctx, cID)
require.NoError(t, err)
assert.Equal(t, inspect.RestartCount, 5)
assert.Equal(t, inspect.HostConfig.RestartPolicy.MaximumRetryCount, 5)
}
func TestUpdateRestartWithAutoRemove(t *testing.T) {
defer setupTest(t)()
client := request.NewAPIClient(t)
ctx := context.Background()
cID := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
c.HostConfig.AutoRemove = true
})
_, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
RestartPolicy: containertypes.RestartPolicy{
Name: "always",
},
})
testutil.ErrorContains(t, err, "Restart policy cannot be updated because AutoRemove is enabled for the container")
}
@@ -9,6 +9,7 @@ import (
swarmtypes "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/docker/docker/integration/internal/swarm"
"github.com/docker/docker/internal/testutil"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -35,7 +36,7 @@ func TestSecretInspect(t *testing.T) {
secret, _, err = client.SecretInspectWithRaw(context.Background(), testName)
require.NoError(t, err)
assert.Equal(t, secret.ID, secretID)
assert.Equal(t, secretID, secretID)
}
func TestSecretList(t *testing.T) {
@@ -124,3 +125,110 @@ func createSecret(ctx context.Context, t *testing.T, client client.APIClient, na
assert.NotEqual(t, secret.ID, "")
return secret.ID
}
func TestSecretsCreate(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
require.NoError(t, err)
ctx := context.Background()
testName := "test_secret"
createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
require.NoError(t, err)
// create an already existin secret, daemon should return a status code of 409
_, err = client.SecretCreate(ctx, swarmtypes.SecretSpec{
Annotations: swarmtypes.Annotations{
Name: testName,
},
Data: []byte("TESTINGDATA"),
})
testutil.ErrorContains(t, err, "already exists")
}
func TestSecretsDelete(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
require.NoError(t, err)
ctx := context.Background()
testName := "test_secret"
secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
require.NoError(t, err)
insp, _, err := client.SecretInspectWithRaw(ctx, secretID)
require.NoError(t, err)
assert.Equal(t, insp.ID, secretID)
err = client.SecretRemove(ctx, secretID)
require.NoError(t, err)
_, _, err = client.SecretInspectWithRaw(ctx, secretID)
testutil.ErrorContains(t, err, "No such secret")
err = client.SecretRemove(ctx, "non-existin")
testutil.ErrorContains(t, err, "No such secret: non-existin")
}
func TestSecretsUpdate(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
defer setupTest(t)()
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
require.NoError(t, err)
ctx := context.Background()
testName := "test_secret"
secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
require.NoError(t, err)
insp, _, err := client.SecretInspectWithRaw(ctx, secretID)
require.NoError(t, err)
assert.Equal(t, insp.ID, secretID)
// test UpdateSecret with full ID
insp.Spec.Labels = map[string]string{"test": "test1"}
err = client.SecretUpdate(ctx, secretID, insp.Version, insp.Spec)
require.NoError(t, err)
insp, _, err = client.SecretInspectWithRaw(ctx, secretID)
require.NoError(t, err)
assert.Equal(t, insp.Spec.Labels["test"], "test1")
// test UpdateSecret with full name
insp.Spec.Labels = map[string]string{"test": "test2"}
err = client.SecretUpdate(ctx, testName, insp.Version, insp.Spec)
require.NoError(t, err)
insp, _, err = client.SecretInspectWithRaw(ctx, secretID)
require.NoError(t, err)
assert.Equal(t, insp.Spec.Labels["test"], "test2")
// test UpdateSecret with prefix ID
insp.Spec.Labels = map[string]string{"test": "test3"}
err = client.SecretUpdate(ctx, secretID[:1], insp.Version, insp.Spec)
require.NoError(t, err)
insp, _, err = client.SecretInspectWithRaw(ctx, secretID)
require.NoError(t, err)
assert.Equal(t, insp.Spec.Labels["test"], "test3")
// test UpdateSecret in updating Data which is not supported in daemon
// this test will produce an error in func UpdateSecret
insp.Spec.Data = []byte("TESTINGDATA2")
err = client.SecretUpdate(ctx, secretID, insp.Version, insp.Spec)
testutil.ErrorContains(t, err, "only updates to Labels are allowed")
}
@@ -223,7 +223,7 @@ func (c *client) createWindows(id string, spec *specs.Spec, runtimeOptions inter
if configuration.HvPartition {
// We don't currently support setting the utility VM image explicitly.
// TODO @swernli/jhowardmsft circa RS3/4, this may be re-locatable.
// TODO @swernli/jhowardmsft circa RS5, this may be re-locatable.
if spec.Windows.HyperV.UtilityVMPath != "" {
return errors.New("runtime does not support an explicit utility VM path for Hyper-V containers")
}
@@ -303,7 +303,7 @@ func (c *client) createWindows(id string, spec *specs.Spec, runtimeOptions inter
}
}
configuration.MappedDirectories = mds
if len(mps) > 0 && system.GetOSVersion().Build < 16210 { // replace with Win10 RS3 build number at RTM
if len(mps) > 0 && system.GetOSVersion().Build < 16299 { // RS3
return errors.New("named pipe mounts are not supported on this version of Windows")
}
configuration.MappedPipes = mps
+1 -1
View File
@@ -35,7 +35,7 @@ func DefaultPathEnv(os string) string {
// This is used, for example, when validating a user provided path in docker cp.
// If a drive letter is supplied, it must be the system drive. The drive letter
// is always removed. Also, it translates it to OS semantics (IOW / to \). We
// need the path in this syntax so that it can ultimately be contatenated with
// need the path in this syntax so that it can ultimately be concatenated with
// a Windows long-path which doesn't support drive-letters. Examples:
// C: --> Fail
// C:\ --> \
+1 -1
View File
@@ -16,7 +16,7 @@ var eol = []byte("\n")
// ErrNonPositiveLinesNumber is an error returned if the lines number was negative.
var ErrNonPositiveLinesNumber = errors.New("The number of lines to extract from the file must be positive")
//TailFile returns last n lines of reader f (could be a fil).
//TailFile returns last n lines of reader f (could be a nil).
func TailFile(f io.ReadSeeker, n int) ([][]byte, error) {
if n <= 0 {
return nil, ErrNonPositiveLinesNumber