2017-05-09 18:35:25 -04:00
|
|
|
package container
|
|
|
|
|
|
|
|
import (
|
2017-08-31 17:07:16 -04:00
|
|
|
"context"
|
2018-03-06 05:15:18 -05:00
|
|
|
"fmt"
|
2017-08-31 17:07:16 -04:00
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
2017-05-09 18:35:25 -04:00
|
|
|
"os"
|
2017-08-02 20:31:32 -04:00
|
|
|
"runtime"
|
2017-08-31 17:07:16 -04:00
|
|
|
"strings"
|
2017-05-09 18:35:25 -04:00
|
|
|
"testing"
|
|
|
|
|
2017-08-31 17:07:16 -04:00
|
|
|
"github.com/docker/cli/internal/test"
|
2018-03-06 05:15:18 -05:00
|
|
|
"github.com/docker/cli/internal/test/notary"
|
2017-08-31 17:07:16 -04:00
|
|
|
"github.com/docker/docker/api/types"
|
|
|
|
"github.com/docker/docker/api/types/container"
|
|
|
|
"github.com/docker/docker/api/types/network"
|
2017-12-21 16:27:57 -05:00
|
|
|
"github.com/google/go-cmp/cmp"
|
2017-08-31 17:07:16 -04:00
|
|
|
"github.com/pkg/errors"
|
2018-06-08 12:24:26 -04:00
|
|
|
"gotest.tools/assert"
|
|
|
|
is "gotest.tools/assert/cmp"
|
|
|
|
"gotest.tools/fs"
|
2018-12-13 06:59:35 -05:00
|
|
|
"gotest.tools/golden"
|
2017-05-09 18:35:25 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestCIDFileNoOPWithNoFilename(t *testing.T) {
|
|
|
|
file, err := newCIDFile("")
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.NilError(t, err)
|
2017-12-21 16:27:57 -05:00
|
|
|
assert.DeepEqual(t, &cidFile{}, file, cmp.AllowUnexported(cidFile{}))
|
2017-05-09 18:35:25 -04:00
|
|
|
|
2018-03-06 15:13:00 -05:00
|
|
|
assert.NilError(t, file.Write("id"))
|
|
|
|
assert.NilError(t, file.Close())
|
2017-05-09 18:35:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewCIDFileWhenFileAlreadyExists(t *testing.T) {
|
|
|
|
tempfile := fs.NewFile(t, "test-cid-file")
|
|
|
|
defer tempfile.Remove()
|
|
|
|
|
|
|
|
_, err := newCIDFile(tempfile.Path())
|
2017-12-21 16:27:57 -05:00
|
|
|
assert.ErrorContains(t, err, "Container ID file found")
|
2017-05-09 18:35:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestCIDFileCloseWithNoWrite(t *testing.T) {
|
|
|
|
tempdir := fs.NewDir(t, "test-cid-file")
|
|
|
|
defer tempdir.Remove()
|
|
|
|
|
|
|
|
path := tempdir.Join("cidfile")
|
|
|
|
file, err := newCIDFile(path)
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Check(t, is.Equal(file.path, path))
|
2017-05-09 18:35:25 -04:00
|
|
|
|
2018-03-06 15:13:00 -05:00
|
|
|
assert.NilError(t, file.Close())
|
2017-05-09 18:35:25 -04:00
|
|
|
_, err = os.Stat(path)
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.Check(t, os.IsNotExist(err))
|
2017-05-09 18:35:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestCIDFileCloseWithWrite(t *testing.T) {
|
|
|
|
tempdir := fs.NewDir(t, "test-cid-file")
|
|
|
|
defer tempdir.Remove()
|
|
|
|
|
|
|
|
path := tempdir.Join("cidfile")
|
|
|
|
file, err := newCIDFile(path)
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.NilError(t, err)
|
2017-05-09 18:35:25 -04:00
|
|
|
|
|
|
|
content := "id"
|
2018-03-06 15:13:00 -05:00
|
|
|
assert.NilError(t, file.Write(content))
|
2017-05-09 18:35:25 -04:00
|
|
|
|
|
|
|
actual, err := ioutil.ReadFile(path)
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Check(t, is.Equal(content, string(actual)))
|
2017-05-09 18:35:25 -04:00
|
|
|
|
2018-03-06 15:13:00 -05:00
|
|
|
assert.NilError(t, file.Close())
|
2017-05-09 18:35:25 -04:00
|
|
|
_, err = os.Stat(path)
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.NilError(t, err)
|
2017-05-09 18:35:25 -04:00
|
|
|
}
|
2017-08-31 17:07:16 -04:00
|
|
|
|
|
|
|
func TestCreateContainerPullsImageIfMissing(t *testing.T) {
|
|
|
|
imageName := "does-not-exist-locally"
|
|
|
|
responseCounter := 0
|
|
|
|
containerID := "abcdef"
|
|
|
|
|
|
|
|
client := &fakeClient{
|
|
|
|
createContainerFunc: func(
|
|
|
|
config *container.Config,
|
|
|
|
hostConfig *container.HostConfig,
|
|
|
|
networkingConfig *network.NetworkingConfig,
|
|
|
|
containerName string,
|
|
|
|
) (container.ContainerCreateCreatedBody, error) {
|
|
|
|
defer func() { responseCounter++ }()
|
|
|
|
switch responseCounter {
|
|
|
|
case 0:
|
|
|
|
return container.ContainerCreateCreatedBody{}, fakeNotFound{}
|
|
|
|
case 1:
|
|
|
|
return container.ContainerCreateCreatedBody{ID: containerID}, nil
|
|
|
|
default:
|
|
|
|
return container.ContainerCreateCreatedBody{}, errors.New("unexpected")
|
|
|
|
}
|
|
|
|
},
|
|
|
|
imageCreateFunc: func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
|
|
|
|
return ioutil.NopCloser(strings.NewReader("")), nil
|
|
|
|
},
|
|
|
|
infoFunc: func() (types.Info, error) {
|
|
|
|
return types.Info{IndexServerAddress: "http://indexserver"}, nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
cli := test.NewFakeCli(client)
|
|
|
|
config := &containerConfig{
|
|
|
|
Config: &container.Config{
|
|
|
|
Image: imageName,
|
|
|
|
},
|
|
|
|
HostConfig: &container.HostConfig{},
|
|
|
|
}
|
2018-03-08 08:35:17 -05:00
|
|
|
body, err := createContainer(context.Background(), cli, config, &createOptions{
|
2018-03-08 14:56:56 -05:00
|
|
|
name: "name",
|
|
|
|
platform: runtime.GOOS,
|
|
|
|
untrusted: true,
|
2018-03-08 08:35:17 -05:00
|
|
|
})
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.NilError(t, err)
|
2017-08-31 17:07:16 -04:00
|
|
|
expected := container.ContainerCreateCreatedBody{ID: containerID}
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.Check(t, is.DeepEqual(expected, *body))
|
2017-08-31 17:07:16 -04:00
|
|
|
stderr := cli.ErrBuffer().String()
|
2018-03-05 18:53:52 -05:00
|
|
|
assert.Check(t, is.Contains(stderr, "Unable to find image 'does-not-exist-locally:latest' locally"))
|
2017-08-31 17:07:16 -04:00
|
|
|
}
|
|
|
|
|
2018-03-06 05:15:18 -05:00
|
|
|
func TestNewCreateCommandWithContentTrustErrors(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
args []string
|
|
|
|
expectedError string
|
|
|
|
notaryFunc test.NotaryClientFuncType
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "offline-notary-server",
|
|
|
|
notaryFunc: notary.GetOfflineNotaryRepository,
|
|
|
|
expectedError: "client is offline",
|
|
|
|
args: []string{"image:tag"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "uninitialized-notary-server",
|
|
|
|
notaryFunc: notary.GetUninitializedNotaryRepository,
|
|
|
|
expectedError: "remote trust data does not exist",
|
|
|
|
args: []string{"image:tag"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "empty-notary-server",
|
|
|
|
notaryFunc: notary.GetEmptyTargetsNotaryRepository,
|
|
|
|
expectedError: "No valid trust data for tag",
|
|
|
|
args: []string{"image:tag"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
|
|
cli := test.NewFakeCli(&fakeClient{
|
|
|
|
createContainerFunc: func(config *container.Config,
|
|
|
|
hostConfig *container.HostConfig,
|
|
|
|
networkingConfig *network.NetworkingConfig,
|
|
|
|
containerName string,
|
|
|
|
) (container.ContainerCreateCreatedBody, error) {
|
|
|
|
return container.ContainerCreateCreatedBody{}, fmt.Errorf("shouldn't try to pull image")
|
|
|
|
},
|
|
|
|
}, test.EnableContentTrust)
|
|
|
|
cli.SetNotaryClient(tc.notaryFunc)
|
|
|
|
cmd := NewCreateCommand(cli)
|
|
|
|
cmd.SetOutput(ioutil.Discard)
|
|
|
|
cmd.SetArgs(tc.args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
assert.ErrorContains(t, err, tc.expectedError)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-13 06:59:35 -05:00
|
|
|
func TestNewCreateCommandWithWarnings(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
args []string
|
|
|
|
warning bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "container-create-without-oom-kill-disable",
|
|
|
|
args: []string{"image:tag"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "container-create-oom-kill-disable-false",
|
|
|
|
args: []string{"--oom-kill-disable=false", "image:tag"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "container-create-oom-kill-without-memory-limit",
|
|
|
|
args: []string{"--oom-kill-disable", "image:tag"},
|
|
|
|
warning: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "container-create-oom-kill-true-without-memory-limit",
|
|
|
|
args: []string{"--oom-kill-disable=true", "image:tag"},
|
|
|
|
warning: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "container-create-oom-kill-true-with-memory-limit",
|
|
|
|
args: []string{"--oom-kill-disable=true", "--memory=100M", "image:tag"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "container-create-localhost-dns",
|
|
|
|
args: []string{"--dns=127.0.0.11", "image:tag"},
|
|
|
|
warning: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "container-create-localhost-dns-ipv6",
|
|
|
|
args: []string{"--dns=::1", "image:tag"},
|
|
|
|
warning: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
cli := test.NewFakeCli(&fakeClient{
|
|
|
|
createContainerFunc: func(config *container.Config,
|
|
|
|
hostConfig *container.HostConfig,
|
|
|
|
networkingConfig *network.NetworkingConfig,
|
|
|
|
containerName string,
|
|
|
|
) (container.ContainerCreateCreatedBody, error) {
|
|
|
|
return container.ContainerCreateCreatedBody{}, nil
|
|
|
|
},
|
|
|
|
})
|
|
|
|
cmd := NewCreateCommand(cli)
|
|
|
|
cmd.SetOutput(ioutil.Discard)
|
|
|
|
cmd.SetArgs(tc.args)
|
|
|
|
err := cmd.Execute()
|
|
|
|
assert.NilError(t, err)
|
|
|
|
if tc.warning {
|
|
|
|
golden.Assert(t, cli.ErrBuffer().String(), tc.name+".golden")
|
|
|
|
} else {
|
|
|
|
assert.Equal(t, cli.ErrBuffer().String(), "")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-31 17:07:16 -04:00
|
|
|
type fakeNotFound struct{}
|
|
|
|
|
|
|
|
func (f fakeNotFound) NotFound() bool { return true }
|
|
|
|
func (f fakeNotFound) Error() string { return "error fake not found" }
|