2014-10-14 21:32:25 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2015-05-01 22:01:10 +00:00
|
|
|
"archive/tar"
|
2014-10-14 21:32:25 +00:00
|
|
|
"bytes"
|
2018-04-19 22:30:59 +00:00
|
|
|
"context"
|
2014-10-14 21:32:25 +00:00
|
|
|
"encoding/json"
|
2015-07-24 21:12:55 +00:00
|
|
|
"fmt"
|
2014-10-14 21:32:25 +00:00
|
|
|
"io"
|
2015-04-14 08:00:46 +00:00
|
|
|
"net/http"
|
2015-05-03 12:54:55 +00:00
|
|
|
"os"
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
"path/filepath"
|
2015-11-26 12:14:09 +00:00
|
|
|
"regexp"
|
2017-08-30 17:10:15 +00:00
|
|
|
"runtime"
|
2014-12-12 16:01:05 +00:00
|
|
|
"strings"
|
2019-09-09 21:06:12 +00:00
|
|
|
"testing"
|
2015-01-20 00:10:26 +00:00
|
|
|
"time"
|
2015-04-11 21:49:14 +00:00
|
|
|
|
2016-09-06 18:18:12 +00:00
|
|
|
"github.com/docker/docker/api/types"
|
2022-04-17 11:47:37 +00:00
|
|
|
"github.com/docker/docker/api/types/container"
|
|
|
|
"github.com/docker/docker/api/types/mount"
|
|
|
|
"github.com/docker/docker/api/types/network"
|
2018-05-04 21:15:00 +00:00
|
|
|
"github.com/docker/docker/api/types/versions"
|
2017-05-24 03:56:26 +00:00
|
|
|
"github.com/docker/docker/client"
|
2022-02-18 17:07:40 +00:00
|
|
|
dconfig "github.com/docker/docker/daemon/config"
|
2022-03-20 15:55:42 +00:00
|
|
|
"github.com/docker/docker/errdefs"
|
2017-04-11 17:42:54 +00:00
|
|
|
"github.com/docker/docker/integration-cli/cli"
|
2017-03-23 17:35:22 +00:00
|
|
|
"github.com/docker/docker/integration-cli/cli/build"
|
2015-04-11 21:49:14 +00:00
|
|
|
"github.com/docker/docker/pkg/stringid"
|
2019-08-29 20:52:40 +00:00
|
|
|
"github.com/docker/docker/testutil/request"
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
"github.com/docker/docker/volume"
|
2017-05-24 03:56:26 +00:00
|
|
|
"github.com/docker/go-connections/nat"
|
2020-02-07 13:39:24 +00:00
|
|
|
"gotest.tools/v3/assert"
|
|
|
|
is "gotest.tools/v3/assert/cmp"
|
|
|
|
"gotest.tools/v3/poll"
|
2014-10-14 21:32:25 +00:00
|
|
|
)
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIGetAll(c *testing.T) {
|
2017-01-16 15:39:12 +00:00
|
|
|
startCount := getContainerCount(c)
|
2014-10-21 22:48:32 +00:00
|
|
|
name := "getall"
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "run", "--name", name, "busybox", "true")
|
2014-10-14 21:32:25 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2014-10-14 21:32:25 +00:00
|
|
|
|
2017-05-24 03:56:26 +00:00
|
|
|
options := types.ContainerListOptions{
|
|
|
|
All: true,
|
2014-10-21 22:48:32 +00:00
|
|
|
}
|
2023-04-03 11:00:29 +00:00
|
|
|
containers, err := apiClient.ContainerList(context.Background(), options)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, len(containers), startCount+1)
|
2017-05-24 03:56:26 +00:00
|
|
|
actual := containers[0].Names[0]
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Equal(c, actual, "/"+name)
|
2014-10-14 21:32:25 +00:00
|
|
|
}
|
|
|
|
|
2015-06-03 16:23:14 +00:00
|
|
|
// regression test for empty json field being omitted #13691
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIGetJSONNoFieldsOmitted(c *testing.T) {
|
2017-05-24 03:56:26 +00:00
|
|
|
startCount := getContainerCount(c)
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "run", "busybox", "true")
|
2015-06-03 16:23:14 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
|
|
|
options := types.ContainerListOptions{
|
|
|
|
All: true,
|
|
|
|
}
|
2023-04-03 11:00:29 +00:00
|
|
|
containers, err := apiClient.ContainerList(context.Background(), options)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, len(containers), startCount+1)
|
2017-05-24 03:56:26 +00:00
|
|
|
actual := fmt.Sprintf("%+v", containers[0])
|
2015-06-03 16:23:14 +00:00
|
|
|
|
|
|
|
// empty Labels field triggered this bug, make sense to check for everything
|
|
|
|
// cause even Ports for instance can trigger this bug
|
|
|
|
// better safe than sorry..
|
|
|
|
fields := []string{
|
2017-05-24 03:56:26 +00:00
|
|
|
"ID",
|
2015-06-03 16:23:14 +00:00
|
|
|
"Names",
|
|
|
|
"Image",
|
|
|
|
"Command",
|
|
|
|
"Created",
|
|
|
|
"Ports",
|
|
|
|
"Labels",
|
|
|
|
"Status",
|
Add containers’ networks to /containers/json
After addition of multi-host networking in Docker 1.9, Docker Remote
API is still returning only the network specified during creation
of the container in the “List Containers” (`/containers/json`) endpoint:
...
"HostConfig": {
"NetworkMode": "default"
},
The list of networks containers are attached to is only available at
Get Container (`/containers/<id>/json`) endpoint.
This does not allow applications utilizing multi-host networking to
be built on top of Docker Remote API.
Therefore I added a simple `"NetworkSettings"` section to the
`/containers/json` endpoint. This is not identical to the NetworkSettings
returned in Get Container (`/containers/<id>/json`) endpoint. It only
contains a single field `"Networks"`, which is essentially the same
value shown in inspect output of a container.
This change adds the following section to the `/containers/json`:
"NetworkSettings": {
"Networks": {
"bridge": {
"EndpointID": "2cdc4edb1ded3631c81f57966563e...",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02"
}
}
}
This is of type `SummaryNetworkSettings` type, a minimal version of
`api/types#NetworkSettings`.
Actually all I need is the network name and the IPAddress fields. If folks
find this addition too big, I can create a `SummaryEndpointSettings` field
as well, containing just the IPAddress field.
Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
2015-12-10 04:48:50 +00:00
|
|
|
"NetworkSettings",
|
2015-06-03 16:23:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// decoding into types.Container do not work since it eventually unmarshal
|
|
|
|
// and empty field to an empty go map, so we just check for a string
|
|
|
|
for _, f := range fields {
|
2017-05-24 03:56:26 +00:00
|
|
|
if !strings.Contains(actual, f) {
|
2015-06-03 16:23:14 +00:00
|
|
|
c.Fatalf("Field %s is missing and it shouldn't", f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIGetExport(c *testing.T) {
|
2016-10-07 00:18:42 +00:00
|
|
|
// Not supported on Windows as Windows does not support docker export
|
2015-08-28 17:36:42 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2014-10-21 22:48:32 +00:00
|
|
|
name := "exportcontainer"
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test")
|
2014-10-14 21:32:25 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2014-10-14 21:32:25 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
body, err := apiClient.ContainerExport(context.Background(), name)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
defer body.Close()
|
2014-10-14 21:32:25 +00:00
|
|
|
found := false
|
2017-05-24 03:56:26 +00:00
|
|
|
for tarReader := tar.NewReader(body); ; {
|
2014-10-14 21:32:25 +00:00
|
|
|
h, err := tarReader.Next()
|
2015-11-19 00:37:42 +00:00
|
|
|
if err != nil && err == io.EOF {
|
|
|
|
break
|
2014-10-14 21:32:25 +00:00
|
|
|
}
|
|
|
|
if h.Name == "test" {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Assert(c, found, "The created test file has not been found in the exported image")
|
2014-10-14 21:32:25 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIGetChanges(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// Not supported on Windows as Windows does not support docker diff (/containers/name/changes)
|
2015-08-28 17:36:42 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2014-10-21 22:48:32 +00:00
|
|
|
name := "changescontainer"
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "run", "--name", name, "busybox", "rm", "/etc/passwd")
|
2014-10-14 21:32:25 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2014-10-14 21:32:25 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
changes, err := apiClient.ContainerDiff(context.Background(), name)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2014-10-14 21:32:25 +00:00
|
|
|
|
|
|
|
// Check the changelog for removal of /etc/passwd
|
|
|
|
success := false
|
|
|
|
for _, elem := range changes {
|
|
|
|
if elem.Path == "/etc/passwd" && elem.Kind == 2 {
|
|
|
|
success = true
|
|
|
|
}
|
|
|
|
}
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Assert(c, success, "/etc/passwd has been removed but is not present in the diff")
|
2014-10-14 21:32:25 +00:00
|
|
|
}
|
2014-12-12 16:01:05 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestGetContainerStats(c *testing.T) {
|
2015-01-21 20:14:28 +00:00
|
|
|
var (
|
2015-07-14 06:35:36 +00:00
|
|
|
name = "statscontainer"
|
2015-01-21 20:14:28 +00:00
|
|
|
)
|
2016-09-07 23:08:51 +00:00
|
|
|
runSleepingContainer(c, "--name", name)
|
2015-07-14 06:35:36 +00:00
|
|
|
|
2015-01-21 20:14:28 +00:00
|
|
|
type b struct {
|
2017-05-24 03:56:26 +00:00
|
|
|
stats types.ContainerStats
|
|
|
|
err error
|
2015-01-21 20:14:28 +00:00
|
|
|
}
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2015-01-21 20:14:28 +00:00
|
|
|
bc := make(chan b, 1)
|
2015-01-20 00:10:26 +00:00
|
|
|
go func() {
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
stats, err := apiClient.ContainerStats(context.Background(), name, true)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
bc <- b{stats, err}
|
2015-01-20 00:10:26 +00:00
|
|
|
}()
|
|
|
|
|
2015-01-21 20:14:28 +00:00
|
|
|
// allow some time to stream the stats from the container
|
|
|
|
time.Sleep(4 * time.Second)
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "rm", "-f", name)
|
2015-01-20 00:10:26 +00:00
|
|
|
|
2015-01-21 20:14:28 +00:00
|
|
|
// collect the results from the stats stream or timeout and fail
|
|
|
|
// if the stream was not disconnected.
|
|
|
|
select {
|
|
|
|
case <-time.After(2 * time.Second):
|
2015-04-18 16:46:47 +00:00
|
|
|
c.Fatal("stream was not closed after container was removed")
|
2015-01-21 20:14:28 +00:00
|
|
|
case sr := <-bc:
|
2017-05-24 03:56:26 +00:00
|
|
|
dec := json.NewDecoder(sr.stats.Body)
|
|
|
|
defer sr.stats.Body.Close()
|
2015-02-24 18:47:47 +00:00
|
|
|
var s *types.Stats
|
2015-01-21 20:14:28 +00:00
|
|
|
// decode only one object from the stream
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, dec.Decode(&s))
|
2015-01-20 00:10:26 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-21 19:08:19 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestGetContainerStatsRmRunning(c *testing.T) {
|
2017-04-16 21:39:30 +00:00
|
|
|
out := runSleepingContainer(c)
|
2015-05-27 02:22:03 +00:00
|
|
|
id := strings.TrimSpace(out)
|
|
|
|
|
2017-08-21 22:44:50 +00:00
|
|
|
buf := &ChannelBuffer{C: make(chan []byte, 1)}
|
2015-05-27 02:22:03 +00:00
|
|
|
defer buf.Close()
|
2016-07-14 23:59:44 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
stats, err := apiClient.ContainerStats(context.Background(), id, true)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
defer stats.Body.Close()
|
2016-07-14 23:59:44 +00:00
|
|
|
|
2016-01-30 03:27:27 +00:00
|
|
|
chErr := make(chan error, 1)
|
2015-05-27 02:22:03 +00:00
|
|
|
go func() {
|
2017-05-24 03:56:26 +00:00
|
|
|
_, err = io.Copy(buf, stats.Body)
|
2015-05-27 02:22:03 +00:00
|
|
|
chErr <- err
|
|
|
|
}()
|
|
|
|
|
|
|
|
b := make([]byte, 32)
|
|
|
|
// make sure we've got some stats
|
2016-07-14 23:59:44 +00:00
|
|
|
_, err = buf.ReadTimeout(b, 2*time.Second)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-05-27 02:22:03 +00:00
|
|
|
|
|
|
|
// Now remove without `-f` and make sure we are still pulling stats
|
2015-07-27 18:13:25 +00:00
|
|
|
_, _, err = dockerCmdWithError("rm", id)
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Assert(c, err != nil, "rm should have failed but didn't")
|
2015-05-27 02:22:03 +00:00
|
|
|
_, err = buf.ReadTimeout(b, 2*time.Second)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-05-27 02:22:03 +00:00
|
|
|
|
2016-07-14 23:59:44 +00:00
|
|
|
dockerCmd(c, "rm", "-f", id)
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, <-chErr == nil)
|
2015-05-27 02:22:03 +00:00
|
|
|
}
|
|
|
|
|
2017-08-21 22:44:50 +00:00
|
|
|
// ChannelBuffer holds a chan of byte array that can be populate in a goroutine.
|
|
|
|
type ChannelBuffer struct {
|
|
|
|
C chan []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write implements Writer.
|
|
|
|
func (c *ChannelBuffer) Write(b []byte) (int, error) {
|
|
|
|
c.C <- b
|
|
|
|
return len(b), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close closes the go channel.
|
|
|
|
func (c *ChannelBuffer) Close() error {
|
|
|
|
close(c.C)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadTimeout reads the content of the channel in the specified byte array with
|
|
|
|
// the specified duration as timeout.
|
|
|
|
func (c *ChannelBuffer) ReadTimeout(p []byte, n time.Duration) (int, error) {
|
|
|
|
select {
|
|
|
|
case b := <-c.C:
|
|
|
|
return copy(p[0:], b), nil
|
|
|
|
case <-time.After(n):
|
|
|
|
return -1, fmt.Errorf("timeout reading from channel")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-23 14:09:39 +00:00
|
|
|
// regression test for gh13421
|
|
|
|
// previous test was just checking one stat entry so it didn't fail (stats with
|
|
|
|
// stream false always return one stat)
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestGetContainerStatsStream(c *testing.T) {
|
2015-05-23 14:09:39 +00:00
|
|
|
name := "statscontainer"
|
2016-09-07 23:08:51 +00:00
|
|
|
runSleepingContainer(c, "--name", name)
|
2015-05-23 14:09:39 +00:00
|
|
|
|
|
|
|
type b struct {
|
2017-05-24 03:56:26 +00:00
|
|
|
stats types.ContainerStats
|
|
|
|
err error
|
2015-05-23 14:09:39 +00:00
|
|
|
}
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2015-05-23 14:09:39 +00:00
|
|
|
bc := make(chan b, 1)
|
|
|
|
go func() {
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
stats, err := apiClient.ContainerStats(context.Background(), name, true)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
bc <- b{stats, err}
|
2015-05-23 14:09:39 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
// allow some time to stream the stats from the container
|
|
|
|
time.Sleep(4 * time.Second)
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "rm", "-f", name)
|
2015-05-23 14:09:39 +00:00
|
|
|
|
|
|
|
// collect the results from the stats stream or timeout and fail
|
|
|
|
// if the stream was not disconnected.
|
|
|
|
select {
|
|
|
|
case <-time.After(2 * time.Second):
|
|
|
|
c.Fatal("stream was not closed after container was removed")
|
|
|
|
case sr := <-bc:
|
2021-08-24 10:10:50 +00:00
|
|
|
b, err := io.ReadAll(sr.stats.Body)
|
2017-05-24 03:56:26 +00:00
|
|
|
defer sr.stats.Body.Close()
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-02-28 16:12:30 +00:00
|
|
|
s := string(b)
|
2015-05-23 14:09:39 +00:00
|
|
|
// count occurrences of "read" of types.Stats
|
|
|
|
if l := strings.Count(s, "read"); l < 2 {
|
|
|
|
c.Fatalf("Expected more than one stat streamed, got %d", l)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestGetContainerStatsNoStream(c *testing.T) {
|
2015-05-23 14:09:39 +00:00
|
|
|
name := "statscontainer"
|
2016-09-07 23:08:51 +00:00
|
|
|
runSleepingContainer(c, "--name", name)
|
2015-05-23 14:09:39 +00:00
|
|
|
|
|
|
|
type b struct {
|
2017-05-24 03:56:26 +00:00
|
|
|
stats types.ContainerStats
|
|
|
|
err error
|
2015-05-23 14:09:39 +00:00
|
|
|
}
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2015-05-23 14:09:39 +00:00
|
|
|
bc := make(chan b, 1)
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2015-05-23 14:09:39 +00:00
|
|
|
go func() {
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
stats, err := apiClient.ContainerStats(context.Background(), name, false)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
bc <- b{stats, err}
|
2015-05-23 14:09:39 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
// allow some time to stream the stats from the container
|
|
|
|
time.Sleep(4 * time.Second)
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "rm", "-f", name)
|
2015-05-23 14:09:39 +00:00
|
|
|
|
|
|
|
// collect the results from the stats stream or timeout and fail
|
|
|
|
// if the stream was not disconnected.
|
|
|
|
select {
|
|
|
|
case <-time.After(2 * time.Second):
|
|
|
|
c.Fatal("stream was not closed after container was removed")
|
|
|
|
case sr := <-bc:
|
2021-08-24 10:10:50 +00:00
|
|
|
b, err := io.ReadAll(sr.stats.Body)
|
2017-05-24 03:56:26 +00:00
|
|
|
defer sr.stats.Body.Close()
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
s := string(b)
|
2016-09-07 23:08:51 +00:00
|
|
|
// count occurrences of `"read"` of types.Stats
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Assert(c, strings.Count(s, `"read"`) == 1, "Expected only one stat streamed, got %d", strings.Count(s, `"read"`))
|
2015-05-23 14:09:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestGetStoppedContainerStats(c *testing.T) {
|
2015-12-30 04:29:31 +00:00
|
|
|
name := "statscontainer"
|
2016-09-07 23:08:51 +00:00
|
|
|
dockerCmd(c, "create", "--name", name, "busybox", "ps")
|
2015-03-16 11:55:34 +00:00
|
|
|
|
2020-02-25 22:13:25 +00:00
|
|
|
chResp := make(chan error, 1)
|
2015-12-30 04:29:31 +00:00
|
|
|
|
|
|
|
// We expect an immediate response, but if it's not immediate, the test would hang, so put it in a goroutine
|
|
|
|
// below we'll check this on a timeout.
|
2015-03-16 11:55:34 +00:00
|
|
|
go func() {
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
resp, err := apiClient.ContainerStats(context.Background(), name, false)
|
2019-08-28 17:56:38 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
defer resp.Body.Close()
|
|
|
|
chResp <- err
|
2015-03-16 11:55:34 +00:00
|
|
|
}()
|
|
|
|
|
2015-12-30 04:29:31 +00:00
|
|
|
select {
|
2017-05-24 03:56:26 +00:00
|
|
|
case err := <-chResp:
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-12-30 04:29:31 +00:00
|
|
|
case <-time.After(10 * time.Second):
|
2016-02-22 19:22:20 +00:00
|
|
|
c.Fatal("timeout waiting for stats response for stopped container")
|
2015-12-30 04:29:31 +00:00
|
|
|
}
|
2015-03-16 11:55:34 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIPause(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// Problematic on Windows as Windows does not support pause
|
2015-08-28 17:36:42 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2017-04-11 17:42:54 +00:00
|
|
|
|
2019-09-09 21:05:55 +00:00
|
|
|
getPaused := func(c *testing.T) []string {
|
2017-04-11 17:42:54 +00:00
|
|
|
return strings.Fields(cli.DockerCmd(c, "ps", "-f", "status=paused", "-q", "-a").Combined())
|
|
|
|
}
|
|
|
|
|
|
|
|
out := cli.DockerCmd(c, "run", "-d", "busybox", "sleep", "30").Combined()
|
2015-04-10 01:14:01 +00:00
|
|
|
ContainerID := strings.TrimSpace(out)
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerPause(context.Background(), ContainerID)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-10 01:14:01 +00:00
|
|
|
|
2017-04-11 17:42:54 +00:00
|
|
|
pausedContainers := getPaused(c)
|
2015-04-10 01:14:01 +00:00
|
|
|
|
|
|
|
if len(pausedContainers) != 1 || stringid.TruncateID(ContainerID) != pausedContainers[0] {
|
2015-04-18 16:46:47 +00:00
|
|
|
c.Fatalf("there should be one paused container and not %d", len(pausedContainers))
|
2015-04-10 01:14:01 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerUnpause(context.Background(), ContainerID)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-10 01:14:01 +00:00
|
|
|
|
2017-04-11 17:42:54 +00:00
|
|
|
pausedContainers = getPaused(c)
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Equal(c, len(pausedContainers), 0, "There should be no paused container.")
|
2015-04-10 01:14:01 +00:00
|
|
|
}
|
2015-04-14 21:14:29 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPITop(c *testing.T) {
|
2015-08-28 17:36:42 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2020-06-30 03:06:03 +00:00
|
|
|
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "top && true")
|
2019-08-05 15:54:15 +00:00
|
|
|
id := strings.TrimSpace(out)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, waitRun(id))
|
2015-04-14 21:14:29 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2018-05-21 17:51:37 +00:00
|
|
|
// sort by comm[andline] to make sure order stays the same in case of PID rollover
|
2023-04-03 11:00:29 +00:00
|
|
|
top, err := apiClient.ContainerTop(context.Background(), id, []string{"aux", "--sort=comm"})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Equal(c, len(top.Titles), 11, fmt.Sprintf("expected 11 titles, found %d: %v", len(top.Titles), top.Titles))
|
2015-04-14 21:14:29 +00:00
|
|
|
|
|
|
|
if top.Titles[0] != "USER" || top.Titles[10] != "COMMAND" {
|
2015-04-18 16:46:47 +00:00
|
|
|
c.Fatalf("expected `USER` at `Titles[0]` and `COMMAND` at Titles[10]: %v", top.Titles)
|
2015-04-14 21:14:29 +00:00
|
|
|
}
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Equal(c, len(top.Processes), 2, fmt.Sprintf("expected 2 processes, found %d: %v", len(top.Processes), top.Processes))
|
2020-06-30 03:06:03 +00:00
|
|
|
assert.Equal(c, top.Processes[0][10], "/bin/sh -c top && true")
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Equal(c, top.Processes[1][10], "top")
|
2015-04-14 21:14:29 +00:00
|
|
|
}
|
2015-04-15 00:48:03 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPITopWindows(c *testing.T) {
|
2016-10-07 00:18:42 +00:00
|
|
|
testRequires(c, DaemonIsWindows)
|
2017-04-16 21:39:30 +00:00
|
|
|
out := runSleepingContainer(c, "-d")
|
2019-08-05 15:54:15 +00:00
|
|
|
id := strings.TrimSpace(out)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, waitRun(id))
|
2016-10-07 00:18:42 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
top, err := apiClient.ContainerTop(context.Background(), id, nil)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, len(top.Titles), 4, "expected 4 titles, found %d: %v", len(top.Titles), top.Titles)
|
2016-10-07 00:18:42 +00:00
|
|
|
|
|
|
|
if top.Titles[0] != "Name" || top.Titles[3] != "Private Working Set" {
|
|
|
|
c.Fatalf("expected `Name` at `Titles[0]` and `Private Working Set` at Titles[3]: %v", top.Titles)
|
|
|
|
}
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Assert(c, len(top.Processes) >= 2, "expected at least 2 processes, found %d: %v", len(top.Processes), top.Processes)
|
2016-10-07 00:18:42 +00:00
|
|
|
|
|
|
|
foundProcess := false
|
|
|
|
expectedProcess := "busybox.exe"
|
|
|
|
for _, process := range top.Processes {
|
|
|
|
if process[0] == expectedProcess {
|
|
|
|
foundProcess = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Assert(c, foundProcess, "expected to find %s: %v", expectedProcess, top.Processes)
|
2016-10-07 00:18:42 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICommit(c *testing.T) {
|
2015-04-25 12:46:47 +00:00
|
|
|
cName := "testapicommit"
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test")
|
2015-04-15 00:48:03 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-04-15 00:48:03 +00:00
|
|
|
|
2017-05-24 03:56:26 +00:00
|
|
|
options := types.ContainerCommitOptions{
|
|
|
|
Reference: "testcontainerapicommit:testtag",
|
2015-04-15 00:48:03 +00:00
|
|
|
}
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
img, err := apiClient.ContainerCommit(context.Background(), cName, options)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-15 00:48:03 +00:00
|
|
|
|
2016-01-28 14:19:25 +00:00
|
|
|
cmd := inspectField(c, img.ID, "Config.Cmd")
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Equal(c, cmd, "[/bin/sh -c touch /test]", fmt.Sprintf("got wrong Cmd from commit: %q", cmd))
|
2015-11-19 00:37:42 +00:00
|
|
|
|
2015-04-15 00:48:03 +00:00
|
|
|
// sanity check, make sure the image is what we think it is
|
2015-07-22 12:59:24 +00:00
|
|
|
dockerCmd(c, "run", img.ID, "ls", "/test")
|
2015-05-30 09:31:51 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICommitWithLabelInConfig(c *testing.T) {
|
2015-05-30 09:31:51 +00:00
|
|
|
cName := "testapicommitwithconfig"
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test")
|
2015-05-30 09:31:51 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-05-30 09:31:51 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Labels: map[string]string{"key1": "value1", "key2": "value2"}}
|
|
|
|
|
|
|
|
options := types.ContainerCommitOptions{
|
|
|
|
Reference: "testcontainerapicommitwithconfig",
|
|
|
|
Config: &config,
|
2015-05-30 09:31:51 +00:00
|
|
|
}
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
img, err := apiClient.ContainerCommit(context.Background(), cName, options)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-05-30 09:31:51 +00:00
|
|
|
|
2016-01-28 14:19:25 +00:00
|
|
|
label1 := inspectFieldMap(c, img.ID, "Config.Labels", "key1")
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Equal(c, label1, "value1")
|
2015-05-30 09:31:51 +00:00
|
|
|
|
2016-01-28 14:19:25 +00:00
|
|
|
label2 := inspectFieldMap(c, img.ID, "Config.Labels", "key2")
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Equal(c, label2, "value2")
|
2015-05-30 09:31:51 +00:00
|
|
|
|
2016-01-28 14:19:25 +00:00
|
|
|
cmd := inspectField(c, img.ID, "Config.Cmd")
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Equal(c, cmd, "[/bin/sh -c touch /test]", fmt.Sprintf("got wrong Cmd from commit: %q", cmd))
|
2015-05-30 09:31:51 +00:00
|
|
|
|
|
|
|
// sanity check, make sure the image is what we think it is
|
2015-07-22 12:59:24 +00:00
|
|
|
dockerCmd(c, "run", img.ID, "ls", "/test")
|
2015-04-15 00:48:03 +00:00
|
|
|
}
|
2015-04-15 01:04:43 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIBadPort(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// TODO Windows to Windows CI - Port this test
|
2015-08-28 17:36:42 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Cmd: []string{"/bin/sh", "-c", "echo test"},
|
|
|
|
}
|
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig := container.HostConfig{
|
2017-05-24 03:56:26 +00:00
|
|
|
PortBindings: nat.PortMap{
|
|
|
|
"8080/tcp": []nat.PortBinding{
|
2015-07-16 03:45:48 +00:00
|
|
|
{
|
2017-05-24 03:56:26 +00:00
|
|
|
HostIP: "",
|
|
|
|
HostPort: "aa80"},
|
2015-07-16 03:45:48 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.ErrorContains(c, err, `invalid port specification: "aa80"`)
|
2015-07-16 03:45:48 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICreate(c *testing.T) {
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Cmd: []string{"/bin/sh", "-c", "touch /test && ls /test"},
|
2015-04-15 01:04:43 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-04-20 21:03:56 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
ctr, err := apiClient.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-15 01:04:43 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
out, _ := dockerCmd(c, "start", "-a", ctr.ID)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, strings.TrimSpace(out), "/test")
|
2015-04-15 01:04:43 +00:00
|
|
|
}
|
2015-04-15 01:55:04 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICreateEmptyConfig(c *testing.T) {
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-06-06 16:41:42 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &container.Config{}, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
2017-05-24 03:56:26 +00:00
|
|
|
|
|
|
|
expected := "No command specified"
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.ErrorContains(c, err, expected)
|
2015-06-06 16:41:42 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICreateMultipleNetworksConfig(c *testing.T) {
|
2016-01-21 22:24:35 +00:00
|
|
|
// Container creation must fail if client specified configurations for more than one network
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
}
|
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
networkingConfig := network.NetworkingConfig{
|
|
|
|
EndpointsConfig: map[string]*network.EndpointSettings{
|
2017-05-24 03:56:26 +00:00
|
|
|
"net1": {},
|
|
|
|
"net2": {},
|
|
|
|
"net3": {},
|
2016-01-21 22:24:35 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &networkingConfig, nil, "")
|
2017-05-24 03:56:26 +00:00
|
|
|
msg := err.Error()
|
2016-01-21 22:24:35 +00:00
|
|
|
// network name order in error message is not deterministic
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Assert(c, strings.Contains(msg, "Container cannot be connected to network endpoints"))
|
|
|
|
assert.Assert(c, strings.Contains(msg, "net1"))
|
|
|
|
assert.Assert(c, strings.Contains(msg, "net2"))
|
|
|
|
assert.Assert(c, strings.Contains(msg, "net3"))
|
2016-01-21 22:24:35 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICreateBridgeNetworkMode(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// Windows does not support bridge
|
2015-08-28 17:36:42 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2015-04-25 08:53:38 +00:00
|
|
|
UtilCreateNetworkMode(c, "bridge")
|
2016-01-08 03:43:11 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICreateOtherNetworkModes(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// Windows does not support these network modes
|
2016-01-08 03:43:11 +00:00
|
|
|
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
|
|
|
UtilCreateNetworkMode(c, "host")
|
2015-04-25 08:53:38 +00:00
|
|
|
UtilCreateNetworkMode(c, "container:web1")
|
|
|
|
}
|
2015-04-22 11:03:57 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
func UtilCreateNetworkMode(c *testing.T, networkMode container.NetworkMode) {
|
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
2015-04-22 11:03:57 +00:00
|
|
|
}
|
2015-04-25 08:53:38 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig := container.HostConfig{
|
2017-05-24 03:56:26 +00:00
|
|
|
NetworkMode: networkMode,
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-04-25 08:53:38 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
ctr, err := apiClient.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-22 11:03:57 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
containerJSON, err := apiClient.ContainerInspect(context.Background(), ctr.ID)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-25 08:53:38 +00:00
|
|
|
|
2019-08-05 15:54:15 +00:00
|
|
|
assert.Equal(c, containerJSON.HostConfig.NetworkMode, networkMode, "Mismatched NetworkMode")
|
2015-04-22 11:03:57 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICreateWithCpuSharesCpuset(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// TODO Windows to Windows CI. The CpuShares part could be ported.
|
2015-08-28 17:36:42 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
2015-05-15 21:00:54 +00:00
|
|
|
}
|
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig := container.HostConfig{
|
|
|
|
Resources: container.Resources{
|
2017-05-24 03:56:26 +00:00
|
|
|
CPUShares: 512,
|
|
|
|
CpusetCpus: "0",
|
|
|
|
},
|
|
|
|
}
|
2015-05-15 21:00:54 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-05-15 21:00:54 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
ctr, err := apiClient.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-05-15 21:00:54 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
containerJSON, err := apiClient.ContainerInspect(context.Background(), ctr.ID)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-05-15 21:00:54 +00:00
|
|
|
|
2016-01-28 14:19:25 +00:00
|
|
|
out := inspectField(c, containerJSON.ID, "HostConfig.CpuShares")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, out, "512")
|
2015-05-15 21:00:54 +00:00
|
|
|
|
2016-01-28 14:19:25 +00:00
|
|
|
outCpuset := inspectField(c, containerJSON.ID, "HostConfig.CpusetCpus")
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Equal(c, outCpuset, "0")
|
2015-05-15 21:00:54 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIVerifyHeader(c *testing.T) {
|
2015-04-15 01:55:04 +00:00
|
|
|
config := map[string]interface{}{
|
|
|
|
"Image": "busybox",
|
|
|
|
}
|
|
|
|
|
2015-04-27 16:33:08 +00:00
|
|
|
create := func(ct string) (*http.Response, io.ReadCloser, error) {
|
2015-04-15 01:55:04 +00:00
|
|
|
jsonData := bytes.NewBuffer(nil)
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, json.NewEncoder(jsonData).Encode(config) == nil)
|
2021-08-24 10:10:50 +00:00
|
|
|
return request.Post("/containers/create", request.RawContent(io.NopCloser(jsonData)), request.ContentType(ct))
|
2015-04-15 01:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Try with no content-type
|
2015-04-27 16:33:08 +00:00
|
|
|
res, body, err := create("")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2018-05-04 21:15:00 +00:00
|
|
|
// todo: we need to figure out a better way to compare between dockerd versions
|
|
|
|
// comparing between daemon API version is not precise.
|
|
|
|
if versions.GreaterThanOrEqualTo(testEnv.DaemonAPIVersion(), "1.32") {
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, res.StatusCode, http.StatusBadRequest)
|
2018-05-04 21:15:00 +00:00
|
|
|
} else {
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Assert(c, res.StatusCode != http.StatusOK)
|
2018-05-04 21:15:00 +00:00
|
|
|
}
|
2015-04-15 01:55:04 +00:00
|
|
|
body.Close()
|
2015-04-20 21:03:56 +00:00
|
|
|
|
2015-04-15 01:55:04 +00:00
|
|
|
// Try with wrong content-type
|
2015-04-27 16:33:08 +00:00
|
|
|
res, body, err = create("application/xml")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2018-05-04 21:15:00 +00:00
|
|
|
if versions.GreaterThanOrEqualTo(testEnv.DaemonAPIVersion(), "1.32") {
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, res.StatusCode, http.StatusBadRequest)
|
2018-05-04 21:15:00 +00:00
|
|
|
} else {
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Assert(c, res.StatusCode != http.StatusOK)
|
2018-05-04 21:15:00 +00:00
|
|
|
}
|
2015-04-15 01:55:04 +00:00
|
|
|
body.Close()
|
|
|
|
|
|
|
|
// now application/json
|
2015-04-27 16:33:08 +00:00
|
|
|
res, body, err = create("application/json")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, res.StatusCode, http.StatusCreated)
|
2015-04-15 01:55:04 +00:00
|
|
|
body.Close()
|
|
|
|
}
|
2015-04-15 02:07:04 +00:00
|
|
|
|
2019-11-27 14:36:45 +00:00
|
|
|
// Issue 14230. daemon should return 500 for invalid port syntax
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIInvalidPortSyntax(c *testing.T) {
|
2015-06-28 10:16:24 +00:00
|
|
|
config := `{
|
|
|
|
"Image": "busybox",
|
|
|
|
"HostConfig": {
|
2016-01-23 19:04:57 +00:00
|
|
|
"NetworkMode": "default",
|
2015-06-28 10:16:24 +00:00
|
|
|
"PortBindings": {
|
|
|
|
"19039;1230": [
|
|
|
|
{}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
2017-03-06 15:35:27 +00:00
|
|
|
res, body, err := request.Post("/containers/create", request.RawString(config), request.JSON)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2018-05-04 21:15:00 +00:00
|
|
|
if versions.GreaterThanOrEqualTo(testEnv.DaemonAPIVersion(), "1.32") {
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, res.StatusCode, http.StatusBadRequest)
|
2018-05-04 21:15:00 +00:00
|
|
|
} else {
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Assert(c, res.StatusCode != http.StatusOK)
|
2018-05-04 21:15:00 +00:00
|
|
|
}
|
2015-06-28 10:16:24 +00:00
|
|
|
|
2017-08-21 22:50:40 +00:00
|
|
|
b, err := request.ReadBody(body)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Assert(c, strings.Contains(string(b[:]), "invalid port"))
|
2015-06-28 10:16:24 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIRestartPolicyInvalidPolicyName(c *testing.T) {
|
2016-06-28 22:33:55 +00:00
|
|
|
config := `{
|
|
|
|
"Image": "busybox",
|
|
|
|
"HostConfig": {
|
|
|
|
"RestartPolicy": {
|
|
|
|
"Name": "something",
|
|
|
|
"MaximumRetryCount": 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
2017-03-06 15:35:27 +00:00
|
|
|
res, body, err := request.Post("/containers/create", request.RawString(config), request.JSON)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2018-05-04 21:15:00 +00:00
|
|
|
if versions.GreaterThanOrEqualTo(testEnv.DaemonAPIVersion(), "1.32") {
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, res.StatusCode, http.StatusBadRequest)
|
2018-05-04 21:15:00 +00:00
|
|
|
} else {
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Assert(c, res.StatusCode != http.StatusOK)
|
2018-05-04 21:15:00 +00:00
|
|
|
}
|
2016-06-28 22:33:55 +00:00
|
|
|
|
2017-08-21 22:50:40 +00:00
|
|
|
b, err := request.ReadBody(body)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Assert(c, strings.Contains(string(b[:]), "invalid restart policy"))
|
2016-06-28 22:33:55 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIRestartPolicyRetryMismatch(c *testing.T) {
|
2016-06-28 22:33:55 +00:00
|
|
|
config := `{
|
|
|
|
"Image": "busybox",
|
|
|
|
"HostConfig": {
|
|
|
|
"RestartPolicy": {
|
|
|
|
"Name": "always",
|
|
|
|
"MaximumRetryCount": 2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
2017-03-06 15:35:27 +00:00
|
|
|
res, body, err := request.Post("/containers/create", request.RawString(config), request.JSON)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2018-05-04 21:15:00 +00:00
|
|
|
if versions.GreaterThanOrEqualTo(testEnv.DaemonAPIVersion(), "1.32") {
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, res.StatusCode, http.StatusBadRequest)
|
2018-05-04 21:15:00 +00:00
|
|
|
} else {
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Assert(c, res.StatusCode != http.StatusOK)
|
2018-05-04 21:15:00 +00:00
|
|
|
}
|
2016-06-28 22:33:55 +00:00
|
|
|
|
2017-08-21 22:50:40 +00:00
|
|
|
b, err := request.ReadBody(body)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Assert(c, strings.Contains(string(b[:]), "maximum retry count cannot be used with restart policy"))
|
2016-06-28 22:33:55 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIRestartPolicyNegativeRetryCount(c *testing.T) {
|
2016-06-28 22:33:55 +00:00
|
|
|
config := `{
|
|
|
|
"Image": "busybox",
|
|
|
|
"HostConfig": {
|
|
|
|
"RestartPolicy": {
|
|
|
|
"Name": "on-failure",
|
|
|
|
"MaximumRetryCount": -2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
2017-03-06 15:35:27 +00:00
|
|
|
res, body, err := request.Post("/containers/create", request.RawString(config), request.JSON)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2018-05-04 21:15:00 +00:00
|
|
|
if versions.GreaterThanOrEqualTo(testEnv.DaemonAPIVersion(), "1.32") {
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, res.StatusCode, http.StatusBadRequest)
|
2018-05-04 21:15:00 +00:00
|
|
|
} else {
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Assert(c, res.StatusCode != http.StatusOK)
|
2018-05-04 21:15:00 +00:00
|
|
|
}
|
2016-06-28 22:33:55 +00:00
|
|
|
|
2017-08-21 22:50:40 +00:00
|
|
|
b, err := request.ReadBody(body)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Assert(c, strings.Contains(string(b[:]), "maximum retry count cannot be negative"))
|
2016-12-01 21:24:30 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIRestartPolicyDefaultRetryCount(c *testing.T) {
|
2016-12-01 21:24:30 +00:00
|
|
|
config := `{
|
|
|
|
"Image": "busybox",
|
|
|
|
"HostConfig": {
|
|
|
|
"RestartPolicy": {
|
|
|
|
"Name": "on-failure",
|
|
|
|
"MaximumRetryCount": 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
2017-03-06 15:35:27 +00:00
|
|
|
res, _, err := request.Post("/containers/create", request.RawString(config), request.JSON)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, res.StatusCode, http.StatusCreated)
|
2016-06-28 22:33:55 +00:00
|
|
|
}
|
|
|
|
|
2015-04-15 02:07:04 +00:00
|
|
|
// Issue 7941 - test to make sure a "null" in JSON is just ignored.
|
|
|
|
// W/o this fix a null in JSON would be parsed into a string var as "null"
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIPostCreateNull(c *testing.T) {
|
2015-04-15 02:07:04 +00:00
|
|
|
config := `{
|
|
|
|
"Hostname":"",
|
|
|
|
"Domainname":"",
|
|
|
|
"Memory":0,
|
|
|
|
"MemorySwap":0,
|
|
|
|
"CpuShares":0,
|
|
|
|
"Cpuset":null,
|
|
|
|
"AttachStdin":true,
|
|
|
|
"AttachStdout":true,
|
|
|
|
"AttachStderr":true,
|
|
|
|
"ExposedPorts":{},
|
|
|
|
"Tty":true,
|
|
|
|
"OpenStdin":true,
|
|
|
|
"StdinOnce":true,
|
|
|
|
"Env":[],
|
|
|
|
"Cmd":"ls",
|
|
|
|
"Image":"busybox",
|
|
|
|
"Volumes":{},
|
|
|
|
"WorkingDir":"",
|
|
|
|
"Entrypoint":null,
|
|
|
|
"NetworkDisabled":false,
|
|
|
|
"OnBuild":null}`
|
|
|
|
|
2017-03-06 15:35:27 +00:00
|
|
|
res, body, err := request.Post("/containers/create", request.RawString(config), request.JSON)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, res.StatusCode, http.StatusCreated)
|
2015-04-15 02:07:04 +00:00
|
|
|
|
2017-08-21 22:50:40 +00:00
|
|
|
b, err := request.ReadBody(body)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-15 02:07:04 +00:00
|
|
|
type createResp struct {
|
2015-07-22 12:59:24 +00:00
|
|
|
ID string
|
2015-04-15 02:07:04 +00:00
|
|
|
}
|
2023-04-03 11:00:29 +00:00
|
|
|
var ctr createResp
|
|
|
|
assert.Assert(c, json.Unmarshal(b, &ctr) == nil)
|
|
|
|
out := inspectField(c, ctr.ID, "HostConfig.CpusetCpus")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, out, "")
|
2015-05-12 06:30:16 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
outMemory := inspectField(c, ctr.ID, "HostConfig.Memory")
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Equal(c, outMemory, "0")
|
2023-04-03 11:00:29 +00:00
|
|
|
outMemorySwap := inspectField(c, ctr.ID, "HostConfig.MemorySwap")
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Equal(c, outMemorySwap, "0")
|
2015-04-15 02:07:04 +00:00
|
|
|
}
|
2015-04-15 22:43:18 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestCreateWithTooLowMemoryLimit(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// TODO Windows: Port once memory is supported
|
2015-08-28 17:36:42 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2015-04-15 22:43:18 +00:00
|
|
|
config := `{
|
|
|
|
"Image": "busybox",
|
|
|
|
"Cmd": "ls",
|
|
|
|
"OpenStdin": true,
|
|
|
|
"CpuShares": 100,
|
|
|
|
"Memory": 524287
|
|
|
|
}`
|
|
|
|
|
2017-03-06 15:35:27 +00:00
|
|
|
res, body, err := request.Post("/containers/create", request.RawString(config), request.JSON)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-08-21 22:50:40 +00:00
|
|
|
b, err2 := request.ReadBody(body)
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, err2 == nil)
|
2015-04-15 22:43:18 +00:00
|
|
|
|
2018-05-04 21:15:00 +00:00
|
|
|
if versions.GreaterThanOrEqualTo(testEnv.DaemonAPIVersion(), "1.32") {
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, res.StatusCode, http.StatusBadRequest)
|
2018-05-04 21:15:00 +00:00
|
|
|
} else {
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Assert(c, res.StatusCode != http.StatusOK)
|
2018-05-04 21:15:00 +00:00
|
|
|
}
|
Set minimum memory limit to 6M, to account for higher startup memory use
For some time, we defined a minimum limit for `--memory` limits to account for
overhead during startup, and to supply a reasonable functional container.
Changes in the runtime (runc) introduced a higher memory footprint during container
startup, which now lead to obscure error-messages that are unfriendly for users:
run --rm --memory=4m alpine echo success
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"process_linux.go:415: setting cgroup config for procHooks process caused \\\"failed to write \\\\\\\"4194304\\\\\\\" to \\\\\\\"/sys/fs/cgroup/memory/docker/1254c8d63f85442e599b17dff895f4543c897755ee3bd9b56d5d3d17724b38d7/memory.limit_in_bytes\\\\\\\": write /sys/fs/cgroup/memory/docker/1254c8d63f85442e599b17dff895f4543c897755ee3bd9b56d5d3d17724b38d7/memory.limit_in_bytes: device or resource busy\\\"\"": unknown.
ERRO[0000] error waiting for container: context canceled
Containers that fail to start because of this limit, will not be marked as OOMKilled,
which makes it harder for users to find the cause of the failure.
Note that _after_ this memory is only required during startup of the container. After
the container was started, the container may not consume this memory, and limits
could (manually) be lowered, for example, an alpine container running only a shell
can run with 512k of memory;
echo 524288 > /sys/fs/cgroup/memory/docker/acdd326419f0898be63b0463cfc81cd17fb34d2dae6f8aa3768ee6a075ca5c86/memory.limit_in_bytes
However, restarting the container will reset that manual limit to the container's
configuration. While `docker container update` would allow for the updated limit to
be persisted, (re)starting the container after updating produces the same error message
again, so we cannot use different limits for `docker run` / `docker create` and `docker update`.
This patch raises the minimum memory limnit to 6M, so that a better error-message is
produced if a user tries to create a container with a memory-limit that is too low:
docker create --memory=4m alpine echo success
docker: Error response from daemon: Minimum memory limit allowed is 6MB.
Possibly, this constraint could be handled by runc, so that different runtimes
could set a best-matching limit (other runtimes may require less overhead).
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2020-07-01 10:04:23 +00:00
|
|
|
assert.Assert(c, strings.Contains(string(b), "Minimum memory limit allowed is 6MB"))
|
2015-04-15 22:43:18 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIRename(c *testing.T) {
|
[nit] integration-cli: obey Go's naming convention
No substantial code change.
- Api --> API
- Cli --> CLI
- Http, Https --> HTTP, HTTPS
- Id --> ID
- Uid,Gid,Pid --> UID,PID,PID
- Ipam --> IPAM
- Tls --> TLS (TestDaemonNoTlsCliTlsVerifyWithEnv --> TestDaemonTLSVerifyIssue13964)
Didn't touch in this commit:
- Git: because it is officially "Git": https://git-scm.com/
- Tar: because it is officially "Tar": https://www.gnu.org/software/tar/
- Cpu, Nat, Mac, Ipc, Shm: for keeping a consistency with existing production code (not changable, for compatibility)
Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
2016-09-28 01:50:12 +00:00
|
|
|
out, _ := dockerCmd(c, "run", "--name", "TestContainerAPIRename", "-d", "busybox", "sh")
|
2015-04-24 11:57:04 +00:00
|
|
|
|
|
|
|
containerID := strings.TrimSpace(out)
|
[nit] integration-cli: obey Go's naming convention
No substantial code change.
- Api --> API
- Cli --> CLI
- Http, Https --> HTTP, HTTPS
- Id --> ID
- Uid,Gid,Pid --> UID,PID,PID
- Ipam --> IPAM
- Tls --> TLS (TestDaemonNoTlsCliTlsVerifyWithEnv --> TestDaemonTLSVerifyIssue13964)
Didn't touch in this commit:
- Git: because it is officially "Git": https://git-scm.com/
- Tar: because it is officially "Tar": https://www.gnu.org/software/tar/
- Cpu, Nat, Mac, Ipc, Shm: for keeping a consistency with existing production code (not changable, for compatibility)
Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
2016-09-28 01:50:12 +00:00
|
|
|
newName := "TestContainerAPIRenameNew"
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerRename(context.Background(), containerID, newName)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-24 11:57:04 +00:00
|
|
|
|
2016-01-28 14:19:25 +00:00
|
|
|
name := inspectField(c, containerID, "Name")
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Equal(c, name, "/"+newName, "Failed to rename container")
|
2015-04-24 11:57:04 +00:00
|
|
|
}
|
2015-04-29 11:56:45 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIKill(c *testing.T) {
|
2015-04-29 11:56:45 +00:00
|
|
|
name := "test-api-kill"
|
2016-01-27 04:16:36 +00:00
|
|
|
runSleepingContainer(c, "-i", "--name", name)
|
2015-04-29 11:56:45 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerKill(context.Background(), name, "SIGKILL")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-29 11:56:45 +00:00
|
|
|
|
2016-01-28 14:19:25 +00:00
|
|
|
state := inspectField(c, name, "State.Running")
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Equal(c, state, "false", fmt.Sprintf("got wrong State from container %s: %q", name, state))
|
2015-04-29 11:56:45 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIRestart(c *testing.T) {
|
2015-04-29 11:56:45 +00:00
|
|
|
name := "test-api-restart"
|
2016-10-07 00:18:42 +00:00
|
|
|
runSleepingContainer(c, "-di", "--name", name)
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-04-29 11:56:45 +00:00
|
|
|
|
2022-02-16 10:36:37 +00:00
|
|
|
timeout := 1
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerRestart(context.Background(), name, container.StopOptions{Timeout: &timeout})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 15*time.Second) == nil)
|
2015-04-29 11:56:45 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIRestartNotimeoutParam(c *testing.T) {
|
2015-05-06 23:49:16 +00:00
|
|
|
name := "test-api-restart-no-timeout-param"
|
2017-04-16 21:39:30 +00:00
|
|
|
out := runSleepingContainer(c, "-di", "--name", name)
|
2015-05-06 23:49:16 +00:00
|
|
|
id := strings.TrimSpace(out)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, waitRun(id))
|
2015-05-06 23:49:16 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerRestart(context.Background(), name, container.StopOptions{})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 15*time.Second) == nil)
|
2015-05-06 23:49:16 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIStart(c *testing.T) {
|
2015-04-29 11:56:45 +00:00
|
|
|
name := "testing-start"
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Cmd: append([]string{"/bin/sh", "-c"}, sleepCommandForDaemonPlatform()...),
|
|
|
|
OpenStdin: true,
|
2015-04-29 11:56:45 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, name)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-29 11:56:45 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-29 11:56:45 +00:00
|
|
|
|
|
|
|
// second call to start should give 304
|
2017-05-24 03:56:26 +00:00
|
|
|
// maybe add ContainerStartWithRaw to test it
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2016-02-24 22:59:11 +00:00
|
|
|
|
|
|
|
// TODO(tibor): figure out why this doesn't work on windows
|
2015-04-29 11:56:45 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIStop(c *testing.T) {
|
2015-04-29 11:56:45 +00:00
|
|
|
name := "test-api-stop"
|
2016-01-27 04:16:36 +00:00
|
|
|
runSleepingContainer(c, "-i", "--name", name)
|
2022-02-16 10:36:37 +00:00
|
|
|
timeout := 30
|
2015-04-29 11:56:45 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerStop(context.Background(), name, container.StopOptions{
|
2022-02-16 10:36:37 +00:00
|
|
|
Timeout: &timeout,
|
|
|
|
})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, waitInspect(name, "{{ .State.Running }}", "false", 60*time.Second) == nil)
|
2015-04-29 11:56:45 +00:00
|
|
|
|
|
|
|
// second call to start should give 304
|
2017-05-24 03:56:26 +00:00
|
|
|
// maybe add ContainerStartWithRaw to test it
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerStop(context.Background(), name, container.StopOptions{
|
2022-02-16 10:36:37 +00:00
|
|
|
Timeout: &timeout,
|
|
|
|
})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-04-29 11:56:45 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIWait(c *testing.T) {
|
2015-04-29 11:56:45 +00:00
|
|
|
name := "test-api-wait"
|
2016-01-27 04:16:36 +00:00
|
|
|
|
|
|
|
sleepCmd := "/bin/sleep"
|
2023-06-14 09:46:00 +00:00
|
|
|
if testEnv.DaemonInfo.OSType == "windows" {
|
2016-01-27 04:16:36 +00:00
|
|
|
sleepCmd = "sleep"
|
|
|
|
}
|
2016-08-03 22:25:27 +00:00
|
|
|
dockerCmd(c, "run", "--name", name, "busybox", sleepCmd, "2")
|
2015-04-29 11:56:45 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-04-29 11:56:45 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
waitResC, errC := apiClient.ContainerWait(context.Background(), name, "")
|
2017-05-24 03:56:26 +00:00
|
|
|
|
|
|
|
select {
|
|
|
|
case err = <-errC:
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-08-28 16:42:16 +00:00
|
|
|
case waitRes := <-waitResC:
|
|
|
|
assert.Equal(c, waitRes.StatusCode, int64(0))
|
2017-05-24 03:56:26 +00:00
|
|
|
}
|
2015-04-29 11:56:45 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICopyNotExistsAnyMore(c *testing.T) {
|
2015-04-29 11:56:45 +00:00
|
|
|
name := "test-container-api-copy"
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test.txt")
|
2015-04-29 11:56:45 +00:00
|
|
|
|
|
|
|
postData := types.CopyConfig{
|
|
|
|
Resource: "/test.txt",
|
|
|
|
}
|
2017-05-24 03:56:26 +00:00
|
|
|
// no copy in client/
|
|
|
|
res, _, err := request.Post("/containers/"+name+"/copy", request.JSONBody(postData))
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, res.StatusCode, http.StatusNotFound)
|
2016-06-03 17:38:03 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICopyPre124(c *testing.T) {
|
2016-10-31 17:15:43 +00:00
|
|
|
testRequires(c, DaemonIsLinux) // Windows only supports 1.25 or later
|
2016-06-03 17:38:03 +00:00
|
|
|
name := "test-container-api-copy"
|
|
|
|
dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test.txt")
|
|
|
|
|
|
|
|
postData := types.CopyConfig{
|
|
|
|
Resource: "/test.txt",
|
|
|
|
}
|
|
|
|
|
2017-05-24 03:56:26 +00:00
|
|
|
res, body, err := request.Post("/v1.23/containers/"+name+"/copy", request.JSONBody(postData))
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, res.StatusCode, http.StatusOK)
|
2015-04-29 11:56:45 +00:00
|
|
|
|
|
|
|
found := false
|
2017-05-24 03:56:26 +00:00
|
|
|
for tarReader := tar.NewReader(body); ; {
|
2015-04-29 11:56:45 +00:00
|
|
|
h, err := tarReader.Next()
|
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
c.Fatal(err)
|
|
|
|
}
|
|
|
|
if h.Name == "test.txt" {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, found)
|
2015-04-29 11:56:45 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICopyResourcePathEmptyPre124(c *testing.T) {
|
2016-10-31 17:15:43 +00:00
|
|
|
testRequires(c, DaemonIsLinux) // Windows only supports 1.25 or later
|
2015-04-29 11:56:45 +00:00
|
|
|
name := "test-container-api-copy-resource-empty"
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test.txt")
|
2015-04-29 11:56:45 +00:00
|
|
|
|
|
|
|
postData := types.CopyConfig{
|
|
|
|
Resource: "",
|
|
|
|
}
|
|
|
|
|
2017-05-24 03:56:26 +00:00
|
|
|
res, body, err := request.Post("/v1.23/containers/"+name+"/copy", request.JSONBody(postData))
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2018-05-04 21:15:00 +00:00
|
|
|
if versions.GreaterThanOrEqualTo(testEnv.DaemonAPIVersion(), "1.32") {
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, res.StatusCode, http.StatusBadRequest)
|
2018-05-04 21:15:00 +00:00
|
|
|
} else {
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Assert(c, res.StatusCode != http.StatusOK)
|
2018-05-04 21:15:00 +00:00
|
|
|
}
|
2017-05-24 03:56:26 +00:00
|
|
|
b, err := request.ReadBody(body)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-09-09 21:35:23 +00:00
|
|
|
assert.Assert(c, is.Regexp("^Path cannot be empty\n$", string(b)))
|
2015-04-29 11:56:45 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICopyResourcePathNotFoundPre124(c *testing.T) {
|
2016-10-31 17:15:43 +00:00
|
|
|
testRequires(c, DaemonIsLinux) // Windows only supports 1.25 or later
|
2015-04-29 11:56:45 +00:00
|
|
|
name := "test-container-api-copy-resource-not-found"
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "run", "--name", name, "busybox")
|
2015-04-29 11:56:45 +00:00
|
|
|
|
|
|
|
postData := types.CopyConfig{
|
|
|
|
Resource: "/notexist",
|
|
|
|
}
|
|
|
|
|
2017-05-24 03:56:26 +00:00
|
|
|
res, body, err := request.Post("/v1.23/containers/"+name+"/copy", request.JSONBody(postData))
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2018-05-04 21:15:00 +00:00
|
|
|
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, res.StatusCode, http.StatusInternalServerError)
|
2018-05-04 21:15:00 +00:00
|
|
|
} else {
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, res.StatusCode, http.StatusNotFound)
|
2018-05-04 21:15:00 +00:00
|
|
|
}
|
2017-05-24 03:56:26 +00:00
|
|
|
b, err := request.ReadBody(body)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-09-09 21:35:23 +00:00
|
|
|
assert.Assert(c, is.Regexp("^Could not find the file /notexist in container "+name+"\n$", string(b)))
|
2015-04-29 11:56:45 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICopyContainerNotFoundPr124(c *testing.T) {
|
2016-10-31 17:15:43 +00:00
|
|
|
testRequires(c, DaemonIsLinux) // Windows only supports 1.25 or later
|
2015-04-29 11:56:45 +00:00
|
|
|
postData := types.CopyConfig{
|
|
|
|
Resource: "/something",
|
|
|
|
}
|
|
|
|
|
2017-05-24 03:56:26 +00:00
|
|
|
res, _, err := request.Post("/v1.23/containers/notexists/copy", request.JSONBody(postData))
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, res.StatusCode, http.StatusNotFound)
|
2015-04-29 11:56:45 +00:00
|
|
|
}
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIDelete(c *testing.T) {
|
2017-04-16 21:39:30 +00:00
|
|
|
out := runSleepingContainer(c)
|
2015-05-03 12:54:55 +00:00
|
|
|
|
|
|
|
id := strings.TrimSpace(out)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, waitRun(id))
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2015-07-14 06:35:36 +00:00
|
|
|
dockerCmd(c, "stop", id)
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerRemove(context.Background(), id, types.ContainerRemoveOptions{})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-05-03 12:54:55 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIDeleteNotExist(c *testing.T) {
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerRemove(context.Background(), "doesnotexist", types.ContainerRemoveOptions{})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.ErrorContains(c, err, "No such container: doesnotexist")
|
2015-05-03 12:54:55 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIDeleteForce(c *testing.T) {
|
2017-04-16 21:39:30 +00:00
|
|
|
out := runSleepingContainer(c)
|
2015-05-03 12:54:55 +00:00
|
|
|
id := strings.TrimSpace(out)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, waitRun(id))
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2017-05-24 03:56:26 +00:00
|
|
|
removeOptions := types.ContainerRemoveOptions{
|
|
|
|
Force: true,
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerRemove(context.Background(), id, removeOptions)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-05-03 12:54:55 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIDeleteRemoveLinks(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// Windows does not support links
|
2015-08-28 17:36:42 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2015-07-14 06:35:36 +00:00
|
|
|
out, _ := dockerCmd(c, "run", "-d", "--name", "tlink1", "busybox", "top")
|
2015-05-03 12:54:55 +00:00
|
|
|
|
|
|
|
id := strings.TrimSpace(out)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, waitRun(id))
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2015-07-14 06:35:36 +00:00
|
|
|
out, _ = dockerCmd(c, "run", "--link", "tlink1:tlink1", "--name", "tlink2", "-d", "busybox", "top")
|
2015-05-03 12:54:55 +00:00
|
|
|
|
|
|
|
id2 := strings.TrimSpace(out)
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, waitRun(id2) == nil)
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2016-01-28 14:19:25 +00:00
|
|
|
links := inspectFieldJSON(c, id2, "HostConfig.Links")
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Equal(c, links, "[\"/tlink1:/tlink2/tlink1\"]", "expected to have links between containers")
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2017-05-24 03:56:26 +00:00
|
|
|
removeOptions := types.ContainerRemoveOptions{
|
|
|
|
RemoveLinks: true,
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerRemove(context.Background(), "tlink2/tlink1", removeOptions)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2016-01-28 14:19:25 +00:00
|
|
|
linksPostRm := inspectFieldJSON(c, id2, "HostConfig.Links")
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Equal(c, linksPostRm, "null", "call to api deleteContainer links should have removed the specified links")
|
2015-05-03 12:54:55 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIDeleteConflict(c *testing.T) {
|
2017-04-16 21:39:30 +00:00
|
|
|
out := runSleepingContainer(c)
|
2015-05-03 12:54:55 +00:00
|
|
|
|
|
|
|
id := strings.TrimSpace(out)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, waitRun(id))
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerRemove(context.Background(), id, types.ContainerRemoveOptions{})
|
2017-05-24 03:56:26 +00:00
|
|
|
expected := "cannot remove a running container"
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.ErrorContains(c, err, expected)
|
2015-05-03 12:54:55 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIDeleteRemoveVolume(c *testing.T) {
|
2018-12-24 12:25:53 +00:00
|
|
|
testRequires(c, testEnv.IsLocalDaemon)
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2016-01-23 19:04:57 +00:00
|
|
|
vol := "/testvolume"
|
2023-06-14 09:46:00 +00:00
|
|
|
if testEnv.DaemonInfo.OSType == "windows" {
|
2016-01-23 19:04:57 +00:00
|
|
|
vol = `c:\testvolume`
|
|
|
|
}
|
|
|
|
|
2017-04-16 21:39:30 +00:00
|
|
|
out := runSleepingContainer(c, "-v", vol)
|
2015-05-03 12:54:55 +00:00
|
|
|
|
|
|
|
id := strings.TrimSpace(out)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, waitRun(id))
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2016-01-23 19:04:57 +00:00
|
|
|
source, err := inspectMountSourceField(id, vol)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-06-03 19:21:38 +00:00
|
|
|
_, err = os.Stat(source)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-05-03 12:54:55 +00:00
|
|
|
|
2017-05-24 03:56:26 +00:00
|
|
|
removeOptions := types.ContainerRemoveOptions{
|
|
|
|
Force: true,
|
|
|
|
RemoveVolumes: true,
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerRemove(context.Background(), id, removeOptions)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2015-11-19 00:37:42 +00:00
|
|
|
_, err = os.Stat(source)
|
2019-09-11 10:57:29 +00:00
|
|
|
assert.Assert(c, os.IsNotExist(err), "expected to get ErrNotExist error, got %v", err)
|
2015-05-03 12:54:55 +00:00
|
|
|
}
|
2015-04-29 17:48:30 +00:00
|
|
|
|
|
|
|
// Regression test for https://github.com/docker/docker/issues/6231
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIChunkedEncoding(c *testing.T) {
|
2016-05-07 10:05:26 +00:00
|
|
|
config := map[string]interface{}{
|
|
|
|
"Image": "busybox",
|
2016-08-17 22:46:28 +00:00
|
|
|
"Cmd": append([]string{"/bin/sh", "-c"}, sleepCommandForDaemonPlatform()...),
|
2016-05-07 10:05:26 +00:00
|
|
|
"OpenStdin": true,
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:22:04 +00:00
|
|
|
resp, _, err := request.Post("/containers/create", request.JSONBody(config), request.With(func(req *http.Request) error {
|
2016-12-30 09:49:36 +00:00
|
|
|
// This is a cheat to make the http request do chunked encoding
|
|
|
|
// Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite
|
|
|
|
// https://golang.org/src/pkg/net/http/request.go?s=11980:12172
|
|
|
|
req.ContentLength = -1
|
|
|
|
return nil
|
2018-04-17 08:22:04 +00:00
|
|
|
}))
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Assert(c, err == nil, "error creating container with chunked encoding")
|
2017-01-11 20:38:52 +00:00
|
|
|
defer resp.Body.Close()
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, resp.StatusCode, http.StatusCreated)
|
2015-04-29 17:48:30 +00:00
|
|
|
}
|
2015-04-27 18:55:11 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIPostContainerStop(c *testing.T) {
|
2017-04-16 21:39:30 +00:00
|
|
|
out := runSleepingContainer(c)
|
2015-04-27 18:55:11 +00:00
|
|
|
|
|
|
|
containerID := strings.TrimSpace(out)
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, waitRun(containerID) == nil)
|
2015-04-27 18:55:11 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerStop(context.Background(), containerID, container.StopOptions{})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, waitInspect(containerID, "{{ .State.Running }}", "false", 60*time.Second) == nil)
|
2015-04-27 18:55:11 +00:00
|
|
|
}
|
2015-06-26 05:15:57 +00:00
|
|
|
|
|
|
|
// #14170
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPostContainerAPICreateWithStringOrSliceEntrypoint(c *testing.T) {
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Entrypoint: []string{"echo"},
|
|
|
|
Cmd: []string{"hello", "world"},
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "echotest")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-06-26 05:15:57 +00:00
|
|
|
out, _ := dockerCmd(c, "start", "-a", "echotest")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, strings.TrimSpace(out), "hello world")
|
2015-06-26 05:15:57 +00:00
|
|
|
|
|
|
|
config2 := struct {
|
|
|
|
Image string
|
2017-05-24 03:56:26 +00:00
|
|
|
Entrypoint string
|
2015-06-26 05:15:57 +00:00
|
|
|
Cmd []string
|
2017-05-24 03:56:26 +00:00
|
|
|
}{"busybox", "echo", []string{"hello", "world"}}
|
|
|
|
_, _, err = request.Post("/containers/create?name=echotest2", request.JSONBody(config2))
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-06-26 05:15:57 +00:00
|
|
|
out, _ = dockerCmd(c, "start", "-a", "echotest2")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, strings.TrimSpace(out), "hello world")
|
2015-06-26 05:15:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// #14170
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPostContainersCreateWithStringOrSliceCmd(c *testing.T) {
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Cmd: []string{"echo", "hello", "world"},
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "echotest")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-06-26 05:15:57 +00:00
|
|
|
out, _ := dockerCmd(c, "start", "-a", "echotest")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, strings.TrimSpace(out), "hello world")
|
2015-06-26 05:15:57 +00:00
|
|
|
|
|
|
|
config2 := struct {
|
2017-05-24 03:56:26 +00:00
|
|
|
Image string
|
|
|
|
Entrypoint string
|
|
|
|
Cmd string
|
|
|
|
}{"busybox", "echo", "hello world"}
|
|
|
|
_, _, err = request.Post("/containers/create?name=echotest2", request.JSONBody(config2))
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-06-26 05:15:57 +00:00
|
|
|
out, _ = dockerCmd(c, "start", "-a", "echotest2")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, strings.TrimSpace(out), "hello world")
|
2015-06-26 05:15:57 +00:00
|
|
|
}
|
2015-07-01 17:59:18 +00:00
|
|
|
|
|
|
|
// regression #14318
|
2018-12-16 15:11:37 +00:00
|
|
|
// for backward compatibility testing with and without CAP_ prefix
|
|
|
|
// and with upper and lowercase
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPostContainersCreateWithStringOrSliceCapAddDrop(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// Windows doesn't support CapAdd/CapDrop
|
2015-08-28 17:36:42 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2015-07-01 17:59:18 +00:00
|
|
|
config := struct {
|
|
|
|
Image string
|
|
|
|
CapAdd string
|
|
|
|
CapDrop string
|
2018-12-16 15:11:37 +00:00
|
|
|
}{"busybox", "NET_ADMIN", "cap_sys_admin"}
|
2017-05-24 03:56:26 +00:00
|
|
|
res, _, err := request.Post("/containers/create?name=capaddtest0", request.JSONBody(config))
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, res.StatusCode, http.StatusCreated)
|
2015-07-01 17:59:18 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
config2 := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
}
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig := container.HostConfig{
|
2018-12-16 15:11:37 +00:00
|
|
|
CapAdd: []string{"net_admin", "SYS_ADMIN"},
|
|
|
|
CapDrop: []string{"SETGID", "CAP_SETPCAP"},
|
2017-05-24 03:56:26 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config2, &hostConfig, &network.NetworkingConfig{}, nil, "capaddtest1")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-07-01 17:59:18 +00:00
|
|
|
}
|
2015-07-21 19:18:56 +00:00
|
|
|
|
2015-07-25 11:39:13 +00:00
|
|
|
// #14915
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICreateNoHostConfig118(c *testing.T) {
|
2016-10-31 17:15:43 +00:00
|
|
|
testRequires(c, DaemonIsLinux) // Windows only support 1.25 or later
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("v1.18"))
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-07-25 11:39:13 +00:00
|
|
|
}
|
2015-07-24 21:12:55 +00:00
|
|
|
|
|
|
|
// Ensure an error occurs when you have a container read-only rootfs but you
|
|
|
|
// extract an archive to a symlink in a writable volume which points to a
|
|
|
|
// directory outside of the volume.
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPutContainerArchiveErrSymlinkInVolumeToReadOnlyRootfs(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// Windows does not support read-only rootfs
|
2015-09-18 17:41:12 +00:00
|
|
|
// Requires local volume mount bind.
|
|
|
|
// --read-only + userns has remount issues
|
2018-12-24 12:25:53 +00:00
|
|
|
testRequires(c, testEnv.IsLocalDaemon, NotUserNamespace, DaemonIsLinux)
|
2015-07-24 21:12:55 +00:00
|
|
|
|
|
|
|
testVol := getTestDir(c, "test-put-container-archive-err-symlink-in-volume-to-read-only-rootfs-")
|
|
|
|
defer os.RemoveAll(testVol)
|
|
|
|
|
|
|
|
makeTestContentInDir(c, testVol)
|
|
|
|
|
|
|
|
cID := makeTestContainer(c, testContainerOptions{
|
|
|
|
readOnly: true,
|
|
|
|
volumes: defaultVolumes(testVol), // Our bind mount is at /vol2
|
|
|
|
})
|
|
|
|
|
|
|
|
// Attempt to extract to a symlink in the volume which points to a
|
|
|
|
// directory outside the volume. This should cause an error because the
|
|
|
|
// rootfs is read-only.
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("v1.20"))
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-07-24 21:12:55 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.CopyToContainer(context.Background(), cID, "/vol2/symlinkToAbsDir", nil, types.CopyToContainerOptions{})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.ErrorContains(c, err, "container rootfs is marked read-only")
|
2015-07-24 21:12:55 +00:00
|
|
|
}
|
2015-09-18 16:39:14 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPostContainersCreateWithWrongCpusetValues(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// Not supported on Windows
|
2015-09-08 18:40:55 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
}
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig1 := container.HostConfig{
|
|
|
|
Resources: container.Resources{
|
2017-05-24 03:56:26 +00:00
|
|
|
CpusetCpus: "1-42,,",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
name := "wrong-cpuset-cpus"
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &hostConfig1, &network.NetworkingConfig{}, nil, name)
|
2016-05-21 11:56:04 +00:00
|
|
|
expected := "Invalid value 1-42,, for cpuset cpus"
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.ErrorContains(c, err, expected)
|
2015-09-08 18:40:55 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig2 := container.HostConfig{
|
|
|
|
Resources: container.Resources{
|
2017-05-24 03:56:26 +00:00
|
|
|
CpusetMems: "42-3,1--",
|
|
|
|
},
|
|
|
|
}
|
2015-09-08 18:40:55 +00:00
|
|
|
name = "wrong-cpuset-mems"
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &hostConfig2, &network.NetworkingConfig{}, nil, name)
|
2016-05-21 11:56:04 +00:00
|
|
|
expected = "Invalid value 42-3,1-- for cpuset mems"
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.ErrorContains(c, err, expected)
|
2015-09-08 18:40:55 +00:00
|
|
|
}
|
2015-11-30 22:44:34 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPostContainersCreateShmSizeNegative(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// ShmSize is not supported on Windows
|
2016-01-08 21:49:43 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
}
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig := container.HostConfig{
|
2017-05-24 03:56:26 +00:00
|
|
|
ShmSize: -1,
|
2015-11-26 12:14:09 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.ErrorContains(c, err, "SHM size can not be less than 0")
|
2015-11-26 12:14:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// ShmSize is not supported on Windows
|
2016-01-08 21:49:43 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2022-02-18 17:07:40 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Cmd: []string{"mount"},
|
2015-11-26 12:14:09 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
ctr, err := apiClient.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
containerJSON, err := apiClient.ContainerInspect(context.Background(), ctr.ID)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2022-02-18 17:07:40 +00:00
|
|
|
assert.Equal(c, containerJSON.HostConfig.ShmSize, dconfig.DefaultShmSize)
|
2015-11-26 12:14:09 +00:00
|
|
|
|
|
|
|
out, _ := dockerCmd(c, "start", "-i", containerJSON.ID)
|
|
|
|
shmRegexp := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=65536k`)
|
|
|
|
if !shmRegexp.MatchString(out) {
|
|
|
|
c.Fatalf("Expected shm of 64MB in mount command, got %v", out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPostContainersCreateShmSizeOmitted(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// ShmSize is not supported on Windows
|
2016-01-08 21:49:43 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Cmd: []string{"mount"},
|
2015-11-26 12:14:09 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
ctr, err := apiClient.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
containerJSON, err := apiClient.ContainerInspect(context.Background(), ctr.ID)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Equal(c, containerJSON.HostConfig.ShmSize, int64(67108864))
|
2015-11-26 12:14:09 +00:00
|
|
|
|
|
|
|
out, _ := dockerCmd(c, "start", "-i", containerJSON.ID)
|
|
|
|
shmRegexp := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=65536k`)
|
|
|
|
if !shmRegexp.MatchString(out) {
|
|
|
|
c.Fatalf("Expected shm of 64MB in mount command, got %v", out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPostContainersCreateWithShmSize(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// ShmSize is not supported on Windows
|
2016-01-08 21:49:43 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Cmd: []string{"mount"},
|
2015-11-26 12:14:09 +00:00
|
|
|
}
|
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig := container.HostConfig{
|
2017-05-24 03:56:26 +00:00
|
|
|
ShmSize: 1073741824,
|
|
|
|
}
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
ctr, err := apiClient.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
containerJSON, err := apiClient.ContainerInspect(context.Background(), ctr.ID)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Equal(c, containerJSON.HostConfig.ShmSize, int64(1073741824))
|
2015-11-26 12:14:09 +00:00
|
|
|
|
|
|
|
out, _ := dockerCmd(c, "start", "-i", containerJSON.ID)
|
|
|
|
shmRegex := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=1048576k`)
|
|
|
|
if !shmRegex.MatchString(out) {
|
|
|
|
c.Fatalf("Expected shm of 1GB in mount command, got %v", out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPostContainersCreateMemorySwappinessHostConfigOmitted(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// Swappiness is not supported on Windows
|
2016-01-08 21:49:43 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
2015-11-26 12:14:09 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
ctr, err := apiClient.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, "")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
containerJSON, err := apiClient.ContainerInspect(context.Background(), ctr.ID)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2015-11-26 12:14:09 +00:00
|
|
|
|
2018-05-04 21:15:00 +00:00
|
|
|
if versions.LessThan(testEnv.DaemonAPIVersion(), "1.31") {
|
2019-09-09 21:05:56 +00:00
|
|
|
assert.Equal(c, *containerJSON.HostConfig.MemorySwappiness, int64(-1))
|
2018-05-04 21:15:00 +00:00
|
|
|
} else {
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, containerJSON.HostConfig.MemorySwappiness == nil)
|
2018-05-04 21:15:00 +00:00
|
|
|
}
|
2015-11-26 12:14:09 +00:00
|
|
|
}
|
2015-10-13 09:26:27 +00:00
|
|
|
|
|
|
|
// check validation is done daemon side and not only in cli
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestPostContainersCreateWithOomScoreAdjInvalidRange(c *testing.T) {
|
2016-01-23 19:04:57 +00:00
|
|
|
// OomScoreAdj is not supported on Windows
|
2015-10-13 09:26:27 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
}
|
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig := container.HostConfig{
|
2017-05-24 03:56:26 +00:00
|
|
|
OomScoreAdj: 1001,
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2015-10-13 09:26:27 +00:00
|
|
|
name := "oomscoreadj-over"
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, name)
|
2016-05-21 11:56:04 +00:00
|
|
|
|
2016-03-22 00:53:57 +00:00
|
|
|
expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]"
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.ErrorContains(c, err, expected)
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig = container.HostConfig{
|
2017-05-24 03:56:26 +00:00
|
|
|
OomScoreAdj: -1001,
|
2015-10-13 09:26:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
name = "oomscoreadj-low"
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, name)
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2016-03-22 00:53:57 +00:00
|
|
|
expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]"
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.ErrorContains(c, err, expected)
|
2015-10-13 09:26:27 +00:00
|
|
|
}
|
2016-04-21 01:33:53 +00:00
|
|
|
|
2016-07-03 17:58:11 +00:00
|
|
|
// test case for #22210 where an empty container name caused panic.
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIDeleteWithEmptyName(c *testing.T) {
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerRemove(context.Background(), "", types.ContainerRemoveOptions{})
|
2022-03-20 15:55:42 +00:00
|
|
|
assert.Check(c, errdefs.IsNotFound(err))
|
2016-04-21 01:33:53 +00:00
|
|
|
}
|
2016-08-20 22:43:15 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPIStatsWithNetworkDisabled(c *testing.T) {
|
2016-08-20 22:43:15 +00:00
|
|
|
// Problematic on Windows as Windows does not support stats
|
|
|
|
testRequires(c, DaemonIsLinux)
|
|
|
|
|
|
|
|
name := "testing-network-disabled"
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Cmd: []string{"top"},
|
|
|
|
NetworkDisabled: true,
|
2016-08-20 22:43:15 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &container.HostConfig{}, &network.NetworkingConfig{}, nil, name)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2016-08-20 22:43:15 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiClient.ContainerStart(context.Background(), name, types.ContainerStartOptions{})
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2016-08-20 22:43:15 +00:00
|
|
|
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, waitRun(name) == nil)
|
2016-08-20 22:43:15 +00:00
|
|
|
|
|
|
|
type b struct {
|
2017-05-24 03:56:26 +00:00
|
|
|
stats types.ContainerStats
|
|
|
|
err error
|
2016-08-20 22:43:15 +00:00
|
|
|
}
|
|
|
|
bc := make(chan b, 1)
|
|
|
|
go func() {
|
2023-04-03 11:00:29 +00:00
|
|
|
stats, err := apiClient.ContainerStats(context.Background(), name, false)
|
2017-05-24 03:56:26 +00:00
|
|
|
bc <- b{stats, err}
|
2016-08-20 22:43:15 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
// allow some time to stream the stats from the container
|
|
|
|
time.Sleep(4 * time.Second)
|
|
|
|
dockerCmd(c, "rm", "-f", name)
|
|
|
|
|
|
|
|
// collect the results from the stats stream or timeout and fail
|
|
|
|
// if the stream was not disconnected.
|
|
|
|
select {
|
|
|
|
case <-time.After(2 * time.Second):
|
|
|
|
c.Fatal("stream was not closed after container was removed")
|
|
|
|
case sr := <-bc:
|
2019-09-09 21:05:57 +00:00
|
|
|
assert.Assert(c, sr.err == nil)
|
2017-05-24 03:56:26 +00:00
|
|
|
sr.stats.Body.Close()
|
2016-08-20 22:43:15 +00:00
|
|
|
}
|
|
|
|
}
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainersAPICreateMountsValidation(c *testing.T) {
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
type testCase struct {
|
2022-04-17 11:47:37 +00:00
|
|
|
config container.Config
|
|
|
|
hostConfig container.HostConfig
|
2017-05-24 03:56:26 +00:00
|
|
|
msg string
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
|
|
|
destPath := prefix + slash + "foo"
|
|
|
|
notExistPath := prefix + slash + "notexist"
|
|
|
|
|
|
|
|
cases := []testCase{
|
2016-09-22 20:14:15 +00:00
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "notreal",
|
|
|
|
Target: destPath,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
msg: "mount type unknown",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "bind"}}},
|
|
|
|
msg: "Target must not be empty",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "bind",
|
|
|
|
Target: destPath}}},
|
|
|
|
msg: "Source must not be empty",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "bind",
|
|
|
|
Source: notExistPath,
|
|
|
|
Target: destPath}}},
|
2018-03-27 16:13:47 +00:00
|
|
|
msg: "source path does not exist",
|
|
|
|
// FIXME(vdemeester) fails into e2e, migrate to integration/container anyway
|
2018-09-28 10:09:52 +00:00
|
|
|
// msg: "source path does not exist: " + notExistPath,
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "volume"}}},
|
|
|
|
msg: "Target must not be empty",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "volume",
|
|
|
|
Source: "hello",
|
|
|
|
Target: destPath}}},
|
|
|
|
msg: "",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "volume",
|
|
|
|
Source: "hello2",
|
|
|
|
Target: destPath,
|
2022-04-17 11:47:37 +00:00
|
|
|
VolumeOptions: &mount.VolumeOptions{
|
|
|
|
DriverConfig: &mount.Driver{
|
2017-05-24 03:56:26 +00:00
|
|
|
Name: "local"}}}}},
|
|
|
|
msg: "",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}
|
|
|
|
|
2018-12-24 12:25:53 +00:00
|
|
|
if testEnv.IsLocalDaemon() {
|
2022-11-23 19:12:51 +00:00
|
|
|
tmpDir, err := os.MkdirTemp("", "test-mounts-api")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
cases = append(cases, []testCase{
|
2016-09-22 20:14:15 +00:00
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "bind",
|
|
|
|
Source: tmpDir,
|
|
|
|
Target: destPath}}},
|
|
|
|
msg: "",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "bind",
|
|
|
|
Source: tmpDir,
|
|
|
|
Target: destPath,
|
2022-04-17 11:47:37 +00:00
|
|
|
VolumeOptions: &mount.VolumeOptions{}}}},
|
2017-05-24 03:56:26 +00:00
|
|
|
msg: "VolumeOptions must not be specified",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}...)
|
|
|
|
}
|
|
|
|
|
2018-12-22 01:28:30 +00:00
|
|
|
if DaemonIsWindows() {
|
|
|
|
cases = append(cases, []testCase{
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2018-12-22 01:28:30 +00:00
|
|
|
Image: "busybox",
|
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{
|
2018-12-22 01:28:30 +00:00
|
|
|
{
|
|
|
|
Type: "volume",
|
|
|
|
Source: "not-supported-on-windows",
|
|
|
|
Target: destPath,
|
2022-04-17 11:47:37 +00:00
|
|
|
VolumeOptions: &mount.VolumeOptions{
|
|
|
|
DriverConfig: &mount.Driver{
|
2018-12-22 01:28:30 +00:00
|
|
|
Name: "local",
|
|
|
|
Options: map[string]string{"type": "tmpfs"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
msg: `options are not supported on this platform`,
|
|
|
|
},
|
|
|
|
}...)
|
|
|
|
}
|
|
|
|
|
2016-12-16 14:13:23 +00:00
|
|
|
if DaemonIsLinux() {
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
cases = append(cases, []testCase{
|
2018-12-22 01:28:30 +00:00
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2018-12-22 01:28:30 +00:00
|
|
|
Image: "busybox",
|
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{
|
2018-12-22 01:28:30 +00:00
|
|
|
{
|
|
|
|
Type: "volume",
|
|
|
|
Source: "missing-device-opt",
|
|
|
|
Target: destPath,
|
2022-04-17 11:47:37 +00:00
|
|
|
VolumeOptions: &mount.VolumeOptions{
|
|
|
|
DriverConfig: &mount.Driver{
|
2018-12-22 01:28:30 +00:00
|
|
|
Name: "local",
|
|
|
|
Options: map[string]string{"foobar": "foobaz"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
msg: `invalid option: "foobar"`,
|
|
|
|
},
|
2016-09-22 20:14:15 +00:00
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{
|
2018-04-09 08:09:30 +00:00
|
|
|
{
|
|
|
|
Type: "volume",
|
|
|
|
Source: "missing-device-opt",
|
|
|
|
Target: destPath,
|
2022-04-17 11:47:37 +00:00
|
|
|
VolumeOptions: &mount.VolumeOptions{
|
|
|
|
DriverConfig: &mount.Driver{
|
2018-04-09 08:09:30 +00:00
|
|
|
Name: "local",
|
|
|
|
Options: map[string]string{"type": "tmpfs"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
msg: `missing required option: "device"`,
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2018-04-09 08:09:30 +00:00
|
|
|
Image: "busybox",
|
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{
|
2018-04-09 08:09:30 +00:00
|
|
|
{
|
|
|
|
Type: "volume",
|
|
|
|
Source: "missing-type-opt",
|
|
|
|
Target: destPath,
|
2022-04-17 11:47:37 +00:00
|
|
|
VolumeOptions: &mount.VolumeOptions{
|
|
|
|
DriverConfig: &mount.Driver{
|
2018-04-09 08:09:30 +00:00
|
|
|
Name: "local",
|
|
|
|
Options: map[string]string{"device": "tmpfs"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
msg: `missing required option: "type"`,
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2018-04-09 08:09:30 +00:00
|
|
|
Image: "busybox",
|
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{
|
2018-04-09 08:09:30 +00:00
|
|
|
{
|
|
|
|
Type: "volume",
|
|
|
|
Source: "hello4",
|
|
|
|
Target: destPath,
|
2022-04-17 11:47:37 +00:00
|
|
|
VolumeOptions: &mount.VolumeOptions{
|
|
|
|
DriverConfig: &mount.Driver{
|
2018-04-09 08:09:30 +00:00
|
|
|
Name: "local",
|
|
|
|
Options: map[string]string{"o": "size=1", "type": "tmpfs", "device": "tmpfs"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2017-05-24 03:56:26 +00:00
|
|
|
msg: "",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "tmpfs",
|
|
|
|
Target: destPath}}},
|
|
|
|
msg: "",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "tmpfs",
|
|
|
|
Target: destPath,
|
2022-04-17 11:47:37 +00:00
|
|
|
TmpfsOptions: &mount.TmpfsOptions{
|
2017-05-24 03:56:26 +00:00
|
|
|
SizeBytes: 4096 * 1024,
|
|
|
|
Mode: 0700,
|
|
|
|
}}}},
|
|
|
|
msg: "",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
config: container.Config{
|
2016-09-22 20:14:15 +00:00
|
|
|
Image: "busybox",
|
2017-05-24 03:56:26 +00:00
|
|
|
},
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig: container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "tmpfs",
|
|
|
|
Source: "/shouldnotbespecified",
|
|
|
|
Target: destPath}}},
|
|
|
|
msg: "Source must not be specified",
|
2016-09-22 20:14:15 +00:00
|
|
|
},
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}...)
|
|
|
|
}
|
2019-10-21 14:02:39 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2019-10-21 14:02:39 +00:00
|
|
|
defer apiClient.Close()
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
|
2018-12-22 01:28:30 +00:00
|
|
|
// TODO add checks for statuscode returned by API
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
for i, x := range cases {
|
2019-10-21 14:02:39 +00:00
|
|
|
x := x
|
|
|
|
c.Run(fmt.Sprintf("case %d", i), func(c *testing.T) {
|
2022-04-17 11:47:37 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &x.config, &x.hostConfig, &network.NetworkingConfig{}, nil, "")
|
2019-10-21 14:02:39 +00:00
|
|
|
if len(x.msg) > 0 {
|
|
|
|
assert.ErrorContains(c, err, x.msg, "%v", cases[i].config)
|
|
|
|
} else {
|
|
|
|
assert.NilError(c, err)
|
|
|
|
}
|
|
|
|
})
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerAPICreateMountsBindRead(c *testing.T) {
|
2018-12-24 12:25:53 +00:00
|
|
|
testRequires(c, NotUserNamespace, testEnv.IsLocalDaemon)
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
// also with data in the host side
|
|
|
|
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
|
|
|
destPath := prefix + slash + "foo"
|
2021-08-24 10:10:50 +00:00
|
|
|
tmpDir, err := os.MkdirTemp("", "test-mounts-api-bind")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
defer os.RemoveAll(tmpDir)
|
2021-08-24 10:10:50 +00:00
|
|
|
err = os.WriteFile(filepath.Join(tmpDir, "bar"), []byte("hello"), 0666)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Cmd: []string{"/bin/sh", "-c", "cat /foo/bar"},
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig := container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{
|
2017-05-24 03:56:26 +00:00
|
|
|
{Type: "bind", Source: tmpDir, Target: destPath},
|
|
|
|
},
|
|
|
|
}
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, "test")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
|
|
|
|
out, _ := dockerCmd(c, "start", "-a", "test")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.Equal(c, out, "hello")
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test Mounts comes out as expected for the MountPoint
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainersAPICreateMountsCreate(c *testing.T) {
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
|
|
|
|
destPath := prefix + slash + "foo"
|
|
|
|
|
|
|
|
var (
|
|
|
|
testImg string
|
|
|
|
)
|
2023-06-14 09:46:00 +00:00
|
|
|
if testEnv.DaemonInfo.OSType != "windows" {
|
2017-01-16 10:30:14 +00:00
|
|
|
testImg = "test-mount-config"
|
2017-03-23 17:35:22 +00:00
|
|
|
buildImageSuccessfully(c, testImg, build.WithDockerfile(`
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
FROM busybox
|
|
|
|
RUN mkdir `+destPath+` && touch `+destPath+slash+`bar
|
|
|
|
CMD cat `+destPath+slash+`bar
|
2017-01-16 10:30:14 +00:00
|
|
|
`))
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
} else {
|
|
|
|
testImg = "busybox"
|
|
|
|
}
|
|
|
|
|
|
|
|
type testCase struct {
|
2022-04-17 11:47:37 +00:00
|
|
|
spec mount.Mount
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
expected types.MountPoint
|
|
|
|
}
|
|
|
|
|
2017-08-30 17:10:15 +00:00
|
|
|
var selinuxSharedLabel string
|
2018-05-04 21:15:00 +00:00
|
|
|
// this test label was added after a bug fix in 1.32, thus add requirements min API >= 1.32
|
|
|
|
// for the sake of making test pass in earlier versions
|
|
|
|
// bug fixed in https://github.com/moby/moby/pull/34684
|
|
|
|
if !versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
|
|
|
|
if runtime.GOOS == "linux" {
|
|
|
|
selinuxSharedLabel = "z"
|
|
|
|
}
|
2017-08-30 17:10:15 +00:00
|
|
|
}
|
|
|
|
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
cases := []testCase{
|
|
|
|
// use literal strings here for `Type` instead of the defined constants in the volume package to keep this honest
|
|
|
|
// Validation of the actual `Mount` struct is done in another test is not needed here
|
2017-09-06 23:32:35 +00:00
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "volume", Target: destPath},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "volume", Target: destPath + slash},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "volume", Target: destPath, Source: "test1"},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Type: "volume", Name: "test1", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "volume", Target: destPath, ReadOnly: true, Source: "test2"},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Type: "volume", Name: "test2", RW: false, Destination: destPath, Mode: selinuxSharedLabel},
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "volume", Target: destPath, Source: "test3", VolumeOptions: &mount.VolumeOptions{DriverConfig: &mount.Driver{Name: volume.DefaultDriverName}}},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", Name: "test3", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
2017-09-06 23:32:35 +00:00
|
|
|
},
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}
|
|
|
|
|
2018-12-24 12:25:53 +00:00
|
|
|
if testEnv.IsLocalDaemon() {
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
// setup temp dir for testing binds
|
2021-08-24 10:10:50 +00:00
|
|
|
tmpDir1, err := os.MkdirTemp("", "test-mounts-api-1")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
defer os.RemoveAll(tmpDir1)
|
|
|
|
cases = append(cases, []testCase{
|
2017-09-06 23:32:35 +00:00
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{
|
2017-09-06 23:32:35 +00:00
|
|
|
Type: "bind",
|
|
|
|
Source: tmpDir1,
|
|
|
|
Target: destPath,
|
|
|
|
},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{
|
2017-09-06 23:32:35 +00:00
|
|
|
Type: "bind",
|
|
|
|
RW: true,
|
|
|
|
Destination: destPath,
|
|
|
|
Source: tmpDir1,
|
|
|
|
},
|
|
|
|
},
|
2017-08-30 17:10:15 +00:00
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "bind", Source: tmpDir1, Target: destPath, ReadOnly: true},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir1},
|
|
|
|
},
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}...)
|
|
|
|
|
|
|
|
// for modes only supported on Linux
|
2016-12-16 14:13:23 +00:00
|
|
|
if DaemonIsLinux() {
|
2022-11-23 19:12:51 +00:00
|
|
|
tmpDir3, err := os.MkdirTemp("", "test-mounts-api-3")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
defer os.RemoveAll(tmpDir3)
|
|
|
|
|
2020-11-05 14:23:49 +00:00
|
|
|
assert.Assert(c, mountWrapper(tmpDir3, tmpDir3, "none", "bind,shared") == nil)
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
|
|
|
|
cases = append(cases, []testCase{
|
2017-08-30 17:10:15 +00:00
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "bind", Source: tmpDir3, Target: destPath},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Type: "bind", RW: true, Destination: destPath, Source: tmpDir3},
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "bind", Source: tmpDir3, Target: destPath, ReadOnly: true},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir3},
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "bind", Source: tmpDir3, Target: destPath, ReadOnly: true, BindOptions: &mount.BindOptions{Propagation: "shared"}},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir3, Propagation: "shared"},
|
|
|
|
},
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-14 09:46:00 +00:00
|
|
|
if testEnv.DaemonInfo.OSType != "windows" { // Windows does not support volume populate
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
cases = append(cases, []testCase{
|
2017-08-30 17:10:15 +00:00
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "volume", Target: destPath, VolumeOptions: &mount.VolumeOptions{NoCopy: true}},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "volume", Target: destPath + slash, VolumeOptions: &mount.VolumeOptions{NoCopy: true}},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "volume", Target: destPath, Source: "test4", VolumeOptions: &mount.VolumeOptions{NoCopy: true}},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Type: "volume", Name: "test4", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
spec: mount.Mount{Type: "volume", Target: destPath, Source: "test5", ReadOnly: true, VolumeOptions: &mount.VolumeOptions{NoCopy: true}},
|
2017-08-30 17:10:15 +00:00
|
|
|
expected: types.MountPoint{Type: "volume", Name: "test5", RW: false, Destination: destPath, Mode: selinuxSharedLabel},
|
|
|
|
},
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}...)
|
|
|
|
}
|
|
|
|
|
2017-09-06 23:32:35 +00:00
|
|
|
ctx := context.Background()
|
|
|
|
apiclient := testEnv.APIClient()
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
for i, x := range cases {
|
2019-10-21 13:57:48 +00:00
|
|
|
x := x
|
|
|
|
c.Run(fmt.Sprintf("%d config: %v", i, x.spec), func(c *testing.T) {
|
2023-04-03 11:00:29 +00:00
|
|
|
ctr, err := apiclient.ContainerCreate(
|
2019-10-21 13:57:48 +00:00
|
|
|
ctx,
|
2022-04-17 11:47:37 +00:00
|
|
|
&container.Config{Image: testImg},
|
|
|
|
&container.HostConfig{Mounts: []mount.Mount{x.spec}},
|
|
|
|
&network.NetworkingConfig{},
|
2020-03-19 20:54:48 +00:00
|
|
|
nil,
|
2019-10-21 13:57:48 +00:00
|
|
|
"")
|
|
|
|
assert.NilError(c, err)
|
2017-09-06 23:32:35 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
containerInspect, err := apiclient.ContainerInspect(ctx, ctr.ID)
|
2019-10-21 13:57:48 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
mps := containerInspect.Mounts
|
|
|
|
assert.Assert(c, is.Len(mps, 1))
|
|
|
|
mountPoint := mps[0]
|
2017-09-06 23:32:35 +00:00
|
|
|
|
2019-10-21 13:57:48 +00:00
|
|
|
if x.expected.Source != "" {
|
|
|
|
assert.Check(c, is.Equal(x.expected.Source, mountPoint.Source))
|
|
|
|
}
|
|
|
|
if x.expected.Name != "" {
|
|
|
|
assert.Check(c, is.Equal(x.expected.Name, mountPoint.Name))
|
|
|
|
}
|
|
|
|
if x.expected.Driver != "" {
|
|
|
|
assert.Check(c, is.Equal(x.expected.Driver, mountPoint.Driver))
|
|
|
|
}
|
|
|
|
if x.expected.Propagation != "" {
|
|
|
|
assert.Check(c, is.Equal(x.expected.Propagation, mountPoint.Propagation))
|
|
|
|
}
|
|
|
|
assert.Check(c, is.Equal(x.expected.RW, mountPoint.RW))
|
|
|
|
assert.Check(c, is.Equal(x.expected.Type, mountPoint.Type))
|
|
|
|
assert.Check(c, is.Equal(x.expected.Mode, mountPoint.Mode))
|
|
|
|
assert.Check(c, is.Equal(x.expected.Destination, mountPoint.Destination))
|
2017-09-06 23:32:35 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiclient.ContainerStart(ctx, ctr.ID, types.ContainerStartOptions{})
|
2019-10-21 13:57:48 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
poll.WaitOn(c, containerExit(apiclient, ctr.ID), poll.WithDelay(time.Second))
|
2017-09-06 23:32:35 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
err = apiclient.ContainerRemove(ctx, ctr.ID, types.ContainerRemoveOptions{
|
2019-10-21 13:57:48 +00:00
|
|
|
RemoveVolumes: true,
|
|
|
|
Force: true,
|
|
|
|
})
|
|
|
|
assert.NilError(c, err)
|
2017-09-06 23:32:35 +00:00
|
|
|
|
2019-10-21 13:57:48 +00:00
|
|
|
switch {
|
|
|
|
// Named volumes still exist after the container is removed
|
|
|
|
case x.spec.Type == "volume" && len(x.spec.Source) > 0:
|
|
|
|
_, err := apiclient.VolumeInspect(ctx, mountPoint.Name)
|
|
|
|
assert.NilError(c, err)
|
2017-09-06 23:32:35 +00:00
|
|
|
|
2019-10-21 13:57:48 +00:00
|
|
|
// Bind mounts are never removed with the container
|
|
|
|
case x.spec.Type == "bind":
|
2017-09-06 23:32:35 +00:00
|
|
|
|
2019-10-21 13:57:48 +00:00
|
|
|
// anonymous volumes are removed
|
|
|
|
default:
|
|
|
|
_, err := apiclient.VolumeInspect(ctx, mountPoint.Name)
|
2023-05-10 11:19:14 +00:00
|
|
|
assert.Check(c, is.ErrorType(err, errdefs.IsNotFound))
|
2019-10-21 13:57:48 +00:00
|
|
|
}
|
|
|
|
})
|
2017-09-06 23:32:35 +00:00
|
|
|
}
|
|
|
|
}
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
|
2017-09-06 23:32:35 +00:00
|
|
|
func containerExit(apiclient client.APIClient, name string) func(poll.LogT) poll.Result {
|
|
|
|
return func(logT poll.LogT) poll.Result {
|
2023-04-03 11:00:29 +00:00
|
|
|
ctr, err := apiclient.ContainerInspect(context.Background(), name)
|
2017-09-06 23:32:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return poll.Error(err)
|
|
|
|
}
|
2023-04-03 11:00:29 +00:00
|
|
|
switch ctr.State.Status {
|
2017-09-06 23:32:35 +00:00
|
|
|
case "created", "running":
|
2023-04-03 11:00:29 +00:00
|
|
|
return poll.Continue("container %s is %s, waiting for exit", name, ctr.State.Status)
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}
|
2017-09-06 23:32:35 +00:00
|
|
|
return poll.Success()
|
Add new `HostConfig` field, `Mounts`.
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-04-26 18:25:35 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-22 20:14:15 +00:00
|
|
|
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainersAPICreateMountsTmpfs(c *testing.T) {
|
2016-09-22 20:14:15 +00:00
|
|
|
testRequires(c, DaemonIsLinux)
|
|
|
|
type testCase struct {
|
2022-04-17 11:47:37 +00:00
|
|
|
cfg mount.Mount
|
2016-09-22 20:14:15 +00:00
|
|
|
expectedOptions []string
|
|
|
|
}
|
|
|
|
target := "/foo"
|
|
|
|
cases := []testCase{
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
cfg: mount.Mount{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "tmpfs",
|
|
|
|
Target: target},
|
2016-09-22 20:14:15 +00:00
|
|
|
expectedOptions: []string{"rw", "nosuid", "nodev", "noexec", "relatime"},
|
|
|
|
},
|
|
|
|
{
|
2022-04-17 11:47:37 +00:00
|
|
|
cfg: mount.Mount{
|
2017-05-24 03:56:26 +00:00
|
|
|
Type: "tmpfs",
|
|
|
|
Target: target,
|
2022-04-17 11:47:37 +00:00
|
|
|
TmpfsOptions: &mount.TmpfsOptions{
|
2017-05-24 03:56:26 +00:00
|
|
|
SizeBytes: 4096 * 1024, Mode: 0700}},
|
2016-09-22 20:14:15 +00:00
|
|
|
expectedOptions: []string{"rw", "nosuid", "nodev", "noexec", "relatime", "size=4096k", "mode=700"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
apiClient, err := client.NewClientWithOpts(client.FromEnv)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2023-04-03 11:00:29 +00:00
|
|
|
defer apiClient.Close()
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2022-04-17 11:47:37 +00:00
|
|
|
config := container.Config{
|
2017-05-24 03:56:26 +00:00
|
|
|
Image: "busybox",
|
|
|
|
Cmd: []string{"/bin/sh", "-c", fmt.Sprintf("mount | grep 'tmpfs on %s'", target)},
|
|
|
|
}
|
2016-09-22 20:14:15 +00:00
|
|
|
for i, x := range cases {
|
|
|
|
cName := fmt.Sprintf("test-tmpfs-%d", i)
|
2022-04-17 11:47:37 +00:00
|
|
|
hostConfig := container.HostConfig{
|
|
|
|
Mounts: []mount.Mount{x.cfg},
|
2016-09-22 20:14:15 +00:00
|
|
|
}
|
2017-05-24 03:56:26 +00:00
|
|
|
|
2023-04-03 11:00:29 +00:00
|
|
|
_, err = apiClient.ContainerCreate(context.Background(), &config, &hostConfig, &network.NetworkingConfig{}, nil, cName)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2016-09-22 20:14:15 +00:00
|
|
|
out, _ := dockerCmd(c, "start", "-a", cName)
|
|
|
|
for _, option := range x.expectedOptions {
|
2019-09-09 21:08:22 +00:00
|
|
|
assert.Assert(c, strings.Contains(out, option))
|
2016-09-22 20:14:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-05-22 13:57:39 +00:00
|
|
|
|
|
|
|
// Regression test for #33334
|
|
|
|
// Makes sure that when a container which has a custom stop signal + restart=always
|
|
|
|
// gets killed (with SIGKILL) by the kill API, that the restart policy is cancelled.
|
2022-06-16 21:32:10 +00:00
|
|
|
func (s *DockerAPISuite) TestContainerKillCustomStopSignal(c *testing.T) {
|
2017-05-22 13:57:39 +00:00
|
|
|
id := strings.TrimSpace(runSleepingContainer(c, "--stop-signal=SIGTERM", "--restart=always"))
|
|
|
|
res, _, err := request.Post("/containers/" + id + "/kill")
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-22 13:57:39 +00:00
|
|
|
defer res.Body.Close()
|
|
|
|
|
2021-08-24 10:10:50 +00:00
|
|
|
b, err := io.ReadAll(res.Body)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
|
|
|
assert.Equal(c, res.StatusCode, http.StatusNoContent, string(b))
|
2017-05-22 13:57:39 +00:00
|
|
|
err = waitInspect(id, "{{.State.Running}} {{.State.Restarting}}", "false false", 30*time.Second)
|
2019-04-04 13:23:19 +00:00
|
|
|
assert.NilError(c, err)
|
2017-05-22 13:57:39 +00:00
|
|
|
}
|