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

This commit is contained in:
GordonTheTurtle
2018-03-21 17:05:26 +00:00
29 changed files with 458 additions and 1404 deletions
-16
View File
@@ -91,21 +91,6 @@ RUN set -x \
FROM base AS notary
# Install notary and notary-server
ENV NOTARY_VERSION v0.5.0
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
go build -buildmode=pie -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
&& rm -rf "$GOPATH"
FROM base AS docker-py
# Get the "docker-py" source so we can run their integration tests
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
@@ -248,7 +233,6 @@ COPY --from=containerd /opt/containerd/ /usr/local/bin/
COPY --from=proxy /opt/proxy/ /usr/local/bin/
COPY --from=dockercli /opt/dockercli /usr/local/cli
COPY --from=registry /usr/local/bin/registry* /usr/local/bin/
COPY --from=notary /usr/local/bin/notary* /usr/local/bin/
COPY --from=criu /opt/criu/ /usr/local/
COPY --from=docker-py /docker-py /docker-py
# TODO: This is for the docker-py tests, which shouldn't really be needed for
+3
View File
@@ -34,6 +34,8 @@ func (daemon *Daemon) execSetPlatformOpt(c *container.Container, ec *exec.Config
if c.AppArmorProfile != "" {
appArmorProfile = c.AppArmorProfile
} else if c.HostConfig.Privileged {
// `docker exec --privileged` does not currently disable AppArmor
// profiles. Privileged configuration of the container is inherited
appArmorProfile = "unconfined"
} else {
appArmorProfile = "docker-default"
@@ -50,6 +52,7 @@ func (daemon *Daemon) execSetPlatformOpt(c *container.Container, ec *exec.Config
return err
}
}
p.ApparmorProfile = appArmorProfile
}
daemon.setRlimits(&specs.Spec{Process: p}, c)
return nil
@@ -0,0 +1,53 @@
// +build linux
package daemon
import (
"testing"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/exec"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/opencontainers/runc/libcontainer/apparmor"
"github.com/opencontainers/runtime-spec/specs-go"
)
func TestExecSetPlatformOpt(t *testing.T) {
if !apparmor.IsEnabled() {
t.Skip("requires AppArmor to be enabled")
}
d := &Daemon{}
c := &container.Container{AppArmorProfile: "my-custom-profile"}
ec := &exec.Config{}
p := &specs.Process{}
err := d.execSetPlatformOpt(c, ec, p)
assert.NilError(t, err)
assert.Equal(t, "my-custom-profile", p.ApparmorProfile)
}
// TestExecSetPlatformOptPrivileged verifies that `docker exec --privileged`
// does not disable AppArmor profiles. Exec currently inherits the `Privileged`
// configuration of the container. See https://github.com/moby/moby/pull/31773#discussion_r105586900
//
// This behavior may change in future, but test for the behavior to prevent it
// from being changed accidentally.
func TestExecSetPlatformOptPrivileged(t *testing.T) {
if !apparmor.IsEnabled() {
t.Skip("requires AppArmor to be enabled")
}
d := &Daemon{}
c := &container.Container{AppArmorProfile: "my-custom-profile"}
ec := &exec.Config{Privileged: true}
p := &specs.Process{}
err := d.execSetPlatformOpt(c, ec, p)
assert.NilError(t, err)
assert.Equal(t, "my-custom-profile", p.ApparmorProfile)
c.HostConfig = &containertypes.HostConfig{Privileged: true}
err = d.execSetPlatformOpt(c, ec, p)
assert.NilError(t, err)
assert.Equal(t, "unconfined", p.ApparmorProfile)
}
@@ -49,6 +49,9 @@ func New(info logger.Info) (logger.Logger, error) {
if err != nil {
return nil, err
}
if capval <= 0 {
return nil, fmt.Errorf("max-size should be a positive numbler")
}
}
var maxFiles = 1
if maxFileString, ok := info.Config["max-file"]; ok {
@@ -62,6 +65,18 @@ func New(info logger.Info) (logger.Logger, error) {
}
}
var compress bool
if compressString, ok := info.Config["compress"]; ok {
var err error
compress, err = strconv.ParseBool(compressString)
if err != nil {
return nil, err
}
if compress && (maxFiles == 1 || capval == -1) {
return nil, fmt.Errorf("compress cannot be true when max-file is less than 2 or max-size is not set")
}
}
attrs, err := info.ExtraAttributes(nil)
if err != nil {
return nil, err
@@ -95,7 +110,7 @@ func New(info logger.Info) (logger.Logger, error) {
return b, nil
}
writer, err := loggerutils.NewLogFile(info.LogPath, capval, maxFiles, marshalFunc, decodeFunc, 0640)
writer, err := loggerutils.NewLogFile(info.LogPath, capval, maxFiles, compress, marshalFunc, decodeFunc, 0640)
if err != nil {
return nil, err
}
@@ -139,6 +154,7 @@ func ValidateLogOpt(cfg map[string]string) error {
switch key {
case "max-file":
case "max-size":
case "compress":
case "labels":
case "env":
case "env-regex":
@@ -2,6 +2,7 @@ package jsonfilelog // import "github.com/docker/docker/daemon/logger/jsonfilelo
import (
"bytes"
"compress/gzip"
"encoding/json"
"io/ioutil"
"os"
@@ -142,7 +143,7 @@ func TestJSONFileLoggerWithOpts(t *testing.T) {
}
defer os.RemoveAll(tmp)
filename := filepath.Join(tmp, "container.log")
config := map[string]string{"max-file": "2", "max-size": "1k"}
config := map[string]string{"max-file": "3", "max-size": "1k", "compress": "true"}
l, err := New(logger.Info{
ContainerID: cid,
LogPath: filename,
@@ -152,21 +153,55 @@ func TestJSONFileLoggerWithOpts(t *testing.T) {
t.Fatal(err)
}
defer l.Close()
for i := 0; i < 20; i++ {
for i := 0; i < 36; i++ {
if err := l.Log(&logger.Message{Line: []byte("line" + strconv.Itoa(i)), Source: "src1"}); err != nil {
t.Fatal(err)
}
}
res, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatal(err)
}
penUlt, err := ioutil.ReadFile(filename + ".1")
if err != nil {
if !os.IsNotExist(err) {
t.Fatal(err)
}
file, err := os.Open(filename + ".1.gz")
defer file.Close()
if err != nil {
t.Fatal(err)
}
zipReader, err := gzip.NewReader(file)
defer zipReader.Close()
if err != nil {
t.Fatal(err)
}
penUlt, err = ioutil.ReadAll(zipReader)
if err != nil {
t.Fatal(err)
}
}
file, err := os.Open(filename + ".2.gz")
defer file.Close()
if err != nil {
t.Fatal(err)
}
zipReader, err := gzip.NewReader(file)
defer zipReader.Close()
if err != nil {
t.Fatal(err)
}
antepenult, err := ioutil.ReadAll(zipReader)
if err != nil {
t.Fatal(err)
}
expectedPenultimate := `{"log":"line0\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
expectedAntepenultimate := `{"log":"line0\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line1\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line2\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line3\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
@@ -183,10 +218,27 @@ func TestJSONFileLoggerWithOpts(t *testing.T) {
{"log":"line14\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line15\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
`
expected := `{"log":"line16\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
expectedPenultimate := `{"log":"line16\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line17\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line18\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line19\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line20\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line21\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line22\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line23\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line24\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line25\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line26\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line27\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line28\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line29\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line30\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line31\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
`
expected := `{"log":"line32\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line33\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line34\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
{"log":"line35\n","stream":"src1","time":"0001-01-01T00:00:00Z"}
`
if string(res) != expected {
@@ -195,7 +247,9 @@ func TestJSONFileLoggerWithOpts(t *testing.T) {
if string(penUlt) != expectedPenultimate {
t.Fatalf("Wrong log content: %q, expected %q", penUlt, expectedPenultimate)
}
if string(antepenult) != expectedAntepenultimate {
t.Fatalf("Wrong log content: %q, expected %q", antepenult, expectedAntepenultimate)
}
}
func TestJSONFileLoggerWithLabelsEnv(t *testing.T) {
@@ -2,17 +2,21 @@ package loggerutils // import "github.com/docker/docker/daemon/logger/loggerutil
import (
"bytes"
"compress/gzip"
"context"
"encoding/json"
"fmt"
"io"
"os"
"strconv"
"strings"
"sync"
"time"
"github.com/docker/docker/daemon/logger"
"github.com/docker/docker/daemon/logger/loggerutils/multireader"
"github.com/docker/docker/pkg/filenotify"
"github.com/docker/docker/pkg/pools"
"github.com/docker/docker/pkg/pubsub"
"github.com/docker/docker/pkg/tailfile"
"github.com/fsnotify/fsnotify"
@@ -20,24 +24,81 @@ import (
"github.com/sirupsen/logrus"
)
const tmpLogfileSuffix = ".tmp"
// rotateFileMetadata is a metadata of the gzip header of the compressed log file
type rotateFileMetadata struct {
LastTime time.Time `json:"lastTime,omitempty"`
}
// refCounter is a counter of logfile being referenced
type refCounter struct {
mu sync.Mutex
counter map[string]int
}
// Reference increase the reference counter for specified logfile
func (rc *refCounter) GetReference(fileName string, openRefFile func(fileName string, exists bool) (*os.File, error)) (*os.File, error) {
rc.mu.Lock()
defer rc.mu.Unlock()
var (
file *os.File
err error
)
_, ok := rc.counter[fileName]
file, err = openRefFile(fileName, ok)
if err != nil {
return nil, err
}
if ok {
rc.counter[fileName]++
} else if file != nil {
rc.counter[file.Name()] = 1
}
return file, nil
}
// Dereference reduce the reference counter for specified logfile
func (rc *refCounter) Dereference(fileName string) error {
rc.mu.Lock()
defer rc.mu.Unlock()
rc.counter[fileName]--
if rc.counter[fileName] <= 0 {
delete(rc.counter, fileName)
err := os.Remove(fileName)
if err != nil {
return err
}
}
return nil
}
// LogFile is Logger implementation for default Docker logging.
type LogFile struct {
f *os.File // store for closing
closed bool
mu sync.RWMutex
capacity int64 //maximum size of each file
currentSize int64 // current size of the latest file
maxFiles int //maximum number of files
notifyRotate *pubsub.Publisher
marshal logger.MarshalFunc
createDecoder makeDecoderFunc
perms os.FileMode
mu sync.RWMutex // protects the logfile access
f *os.File // store for closing
closed bool
rotateMu sync.Mutex // blocks the next rotation until the current rotation is completed
capacity int64 // maximum size of each file
currentSize int64 // current size of the latest file
maxFiles int // maximum number of files
compress bool // whether old versions of log files are compressed
lastTimestamp time.Time // timestamp of the last log
filesRefCounter refCounter // keep reference-counted of decompressed files
notifyRotate *pubsub.Publisher
marshal logger.MarshalFunc
createDecoder makeDecoderFunc
perms os.FileMode
}
type makeDecoderFunc func(rdr io.Reader) func() (*logger.Message, error)
//NewLogFile creates new LogFile
func NewLogFile(logPath string, capacity int64, maxFiles int, marshaller logger.MarshalFunc, decodeFunc makeDecoderFunc, perms os.FileMode) (*LogFile, error) {
func NewLogFile(logPath string, capacity int64, maxFiles int, compress bool, marshaller logger.MarshalFunc, decodeFunc makeDecoderFunc, perms os.FileMode) (*LogFile, error) {
log, err := os.OpenFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, perms)
if err != nil {
return nil, err
@@ -49,14 +110,16 @@ func NewLogFile(logPath string, capacity int64, maxFiles int, marshaller logger.
}
return &LogFile{
f: log,
capacity: capacity,
currentSize: size,
maxFiles: maxFiles,
notifyRotate: pubsub.NewPublisher(0, 1),
marshal: marshaller,
createDecoder: decodeFunc,
perms: perms,
f: log,
capacity: capacity,
currentSize: size,
maxFiles: maxFiles,
compress: compress,
filesRefCounter: refCounter{counter: make(map[string]int)},
notifyRotate: pubsub.NewPublisher(0, 1),
marshal: marshaller,
createDecoder: decodeFunc,
perms: perms,
}, nil
}
@@ -84,6 +147,7 @@ func (w *LogFile) WriteLogEntry(msg *logger.Message) error {
n, err := w.f.Write(b)
if err == nil {
w.currentSize += int64(n)
w.lastTimestamp = msg.Timestamp
}
w.mu.Unlock()
return err
@@ -95,43 +159,108 @@ func (w *LogFile) checkCapacityAndRotate() error {
}
if w.currentSize >= w.capacity {
name := w.f.Name()
w.rotateMu.Lock()
fname := w.f.Name()
if err := w.f.Close(); err != nil {
w.rotateMu.Unlock()
return errors.Wrap(err, "error closing file")
}
if err := rotate(name, w.maxFiles); err != nil {
if err := rotate(fname, w.maxFiles, w.compress); err != nil {
w.rotateMu.Unlock()
return err
}
file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, w.perms)
file, err := os.OpenFile(fname, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, w.perms)
if err != nil {
w.rotateMu.Unlock()
return err
}
w.f = file
w.currentSize = 0
w.notifyRotate.Publish(struct{}{})
if w.maxFiles <= 1 || !w.compress {
w.rotateMu.Unlock()
return nil
}
go func() {
compressFile(fname+".1", w.lastTimestamp)
w.rotateMu.Unlock()
}()
}
return nil
}
func rotate(name string, maxFiles int) error {
func rotate(name string, maxFiles int, compress bool) error {
if maxFiles < 2 {
return nil
}
var extension string
if compress {
extension = ".gz"
}
for i := maxFiles - 1; i > 1; i-- {
toPath := name + "." + strconv.Itoa(i)
fromPath := name + "." + strconv.Itoa(i-1)
toPath := name + "." + strconv.Itoa(i) + extension
fromPath := name + "." + strconv.Itoa(i-1) + extension
if err := os.Rename(fromPath, toPath); err != nil && !os.IsNotExist(err) {
return errors.Wrap(err, "error rotating old log entries")
return err
}
}
if err := os.Rename(name, name+".1"); err != nil && !os.IsNotExist(err) {
return errors.Wrap(err, "error rotating current log")
return err
}
return nil
}
func compressFile(fileName string, lastTimestamp time.Time) {
file, err := os.Open(fileName)
if err != nil {
logrus.Errorf("Failed to open log file: %v", err)
return
}
defer func() {
file.Close()
err := os.Remove(fileName)
if err != nil {
logrus.Errorf("Failed to remove source log file: %v", err)
}
}()
outFile, err := os.OpenFile(fileName+".gz", os.O_CREATE|os.O_RDWR, 0640)
if err != nil {
logrus.Errorf("Failed to open or create gzip log file: %v", err)
return
}
defer func() {
outFile.Close()
if err != nil {
os.Remove(fileName + ".gz")
}
}()
compressWriter := gzip.NewWriter(outFile)
defer compressWriter.Close()
// Add the last log entry timestramp to the gzip header
extra := rotateFileMetadata{}
extra.LastTime = lastTimestamp
compressWriter.Header.Extra, err = json.Marshal(&extra)
if err != nil {
// Here log the error only and don't return since this is just an optimization.
logrus.Warningf("Failed to marshal JSON: %v", err)
}
_, err = pools.Copy(compressWriter, file)
if err != nil {
logrus.WithError(err).WithField("module", "container.logs").WithField("file", fileName).Error("Error compressing log file")
return
}
}
// MaxFiles return maximum number of files
func (w *LogFile) MaxFiles() int {
return w.maxFiles
@@ -154,18 +283,6 @@ func (w *LogFile) Close() error {
// ReadLogs decodes entries from log files and sends them the passed in watcher
func (w *LogFile) ReadLogs(config logger.ReadConfig, watcher *logger.LogWatcher) {
w.mu.RLock()
files, err := w.openRotatedFiles()
if err != nil {
w.mu.RUnlock()
watcher.Err <- err
return
}
defer func() {
for _, f := range files {
f.Close()
}
}()
currentFile, err := os.Open(w.f.Name())
if err != nil {
w.mu.RUnlock()
@@ -175,14 +292,20 @@ func (w *LogFile) ReadLogs(config logger.ReadConfig, watcher *logger.LogWatcher)
defer currentFile.Close()
currentChunk, err := newSectionReader(currentFile)
w.mu.RUnlock()
if err != nil {
w.mu.RUnlock()
watcher.Err <- err
return
}
if config.Tail != 0 {
files, err := w.openRotatedFiles(config)
if err != nil {
w.mu.RUnlock()
watcher.Err <- err
return
}
w.mu.RUnlock()
seekers := make([]io.ReadSeeker, 0, len(files)+1)
for _, f := range files {
seekers = append(seekers, f)
@@ -193,9 +316,20 @@ func (w *LogFile) ReadLogs(config logger.ReadConfig, watcher *logger.LogWatcher)
if len(seekers) > 0 {
tailFile(multireader.MultiReadSeeker(seekers...), watcher, w.createDecoder, config)
}
for _, f := range files {
f.Close()
fileName := f.Name()
if strings.HasSuffix(fileName, tmpLogfileSuffix) {
err := w.filesRefCounter.Dereference(fileName)
if err != nil {
logrus.Errorf("Failed to dereference the log file %q: %v", fileName, err)
}
}
}
w.mu.RLock()
}
w.mu.RLock()
if !config.Follow || w.closed {
w.mu.RUnlock()
return
@@ -207,13 +341,22 @@ func (w *LogFile) ReadLogs(config logger.ReadConfig, watcher *logger.LogWatcher)
followLogs(currentFile, watcher, notifyRotate, w.createDecoder, config.Since, config.Until)
}
func (w *LogFile) openRotatedFiles() (files []*os.File, err error) {
func (w *LogFile) openRotatedFiles(config logger.ReadConfig) (files []*os.File, err error) {
w.rotateMu.Lock()
defer w.rotateMu.Unlock()
defer func() {
if err == nil {
return
}
for _, f := range files {
f.Close()
if strings.HasSuffix(f.Name(), tmpLogfileSuffix) {
err := os.Remove(f.Name())
if err != nil && !os.IsNotExist(err) {
logrus.Warningf("Failed to remove the logfile %q: %v", f.Name, err)
}
}
}
}()
@@ -223,6 +366,28 @@ func (w *LogFile) openRotatedFiles() (files []*os.File, err error) {
if !os.IsNotExist(err) {
return nil, err
}
fileName := fmt.Sprintf("%s.%d.gz", w.f.Name(), i-1)
decompressedFileName := fileName + tmpLogfileSuffix
tmpFile, err := w.filesRefCounter.GetReference(decompressedFileName, func(refFileName string, exists bool) (*os.File, error) {
if exists {
return os.Open(refFileName)
}
return decompressfile(fileName, refFileName, config.Since)
})
if err != nil {
if !os.IsNotExist(err) {
return nil, err
}
continue
}
if tmpFile == nil {
// The log before `config.Since` does not need to read
break
}
files = append(files, tmpFile)
continue
}
files = append(files, f)
@@ -231,6 +396,44 @@ func (w *LogFile) openRotatedFiles() (files []*os.File, err error) {
return files, nil
}
func decompressfile(fileName, destFileName string, since time.Time) (*os.File, error) {
cf, err := os.Open(fileName)
if err != nil {
return nil, err
}
defer cf.Close()
rc, err := gzip.NewReader(cf)
if err != nil {
return nil, err
}
defer rc.Close()
// Extract the last log entry timestramp from the gzip header
extra := &rotateFileMetadata{}
err = json.Unmarshal(rc.Header.Extra, extra)
if err == nil && extra.LastTime.Before(since) {
return nil, nil
}
rs, err := os.OpenFile(destFileName, os.O_CREATE|os.O_RDWR, 0640)
if err != nil {
return nil, err
}
_, err = pools.Copy(rs, rc)
if err != nil {
rs.Close()
rErr := os.Remove(rs.Name())
if rErr != nil && os.IsNotExist(rErr) {
logrus.Errorf("Failed to remove the logfile %q: %v", rs.Name(), rErr)
}
return nil, err
}
return rs, nil
}
func newSectionReader(f *os.File) (*io.SectionReader, error) {
// seek to the end to get the size
// we'll leave this at the end of the file since section reader does not advance the reader
+3 -3
View File
@@ -13,8 +13,8 @@ export DOCKER_ENGINE_GOARCH=${DOCKER_ENGINE_GOARCH:-${ARCH}}
: ${TESTDEBUG:=}
integration_api_dirs=${TEST_INTEGRATION_DIR:-"$(
find ./integration -type d |
grep -vE '(^./integration($|/internal)|/testdata)')"}
find /tests/integration -type d |
grep -vE '(^/tests/integration($|/internal)|/testdata)')"}
run_test_integration() {
[[ "$TESTFLAGS" != *-check.f* ]] && run_test_integration_suites
@@ -35,7 +35,7 @@ run_test_integration_suites() {
run_test_integration_legacy_suites() {
(
flags="-check.v -check.timeout=${TIMEOUT} -test.timeout=360m $TESTFLAGS"
cd test/integration-cli
cd /tests/integration-cli
echo "Running $PWD"
test_env ./test.main $flags
)
@@ -14,7 +14,6 @@ import (
"time"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/cli/config"
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/integration-cli/cli"
"github.com/docker/docker/integration-cli/cli/build/fakestorage"
@@ -386,74 +385,6 @@ func (s *DockerSwarmSuite) TearDownTest(c *check.C) {
s.ds.TearDownTest(c)
}
func init() {
check.Suite(&DockerTrustSuite{
ds: &DockerSuite{},
})
}
type DockerTrustSuite struct {
ds *DockerSuite
reg *registry.V2
not *testNotary
}
func (s *DockerTrustSuite) OnTimeout(c *check.C) {
s.ds.OnTimeout(c)
}
func (s *DockerTrustSuite) SetUpTest(c *check.C) {
testRequires(c, registry.Hosting, NotaryServerHosting)
s.reg = setupRegistry(c, false, "", "")
s.not = setupNotary(c)
}
func (s *DockerTrustSuite) TearDownTest(c *check.C) {
if s.reg != nil {
s.reg.Close()
}
if s.not != nil {
s.not.Close()
}
// Remove trusted keys and metadata after test
os.RemoveAll(filepath.Join(config.Dir(), "trust"))
s.ds.TearDownTest(c)
}
func init() {
ds := &DockerSuite{}
check.Suite(&DockerTrustedSwarmSuite{
trustSuite: DockerTrustSuite{
ds: ds,
},
swarmSuite: DockerSwarmSuite{
ds: ds,
},
})
}
type DockerTrustedSwarmSuite struct {
swarmSuite DockerSwarmSuite
trustSuite DockerTrustSuite
reg *registry.V2
not *testNotary
}
func (s *DockerTrustedSwarmSuite) SetUpTest(c *check.C) {
s.swarmSuite.SetUpTest(c)
s.trustSuite.SetUpTest(c)
}
func (s *DockerTrustedSwarmSuite) TearDownTest(c *check.C) {
s.trustSuite.TearDownTest(c)
s.swarmSuite.TearDownTest(c)
}
func (s *DockerTrustedSwarmSuite) OnTimeout(c *check.C) {
s.swarmSuite.OnTimeout(c)
}
func init() {
check.Suite(&DockerPluginSuite{
ds: &DockerSuite{},
@@ -4048,140 +4048,6 @@ func (s *DockerSuite) TestBuildRUNErrMsg(c *check.C) {
})
}
func (s *DockerTrustSuite) TestTrustedBuild(c *check.C) {
repoName := s.setupTrustedImage(c, "trusted-build")
dockerFile := fmt.Sprintf(`
FROM %s
RUN []
`, repoName)
name := "testtrustedbuild"
buildImage(name, trustedBuild, build.WithDockerfile(dockerFile)).Assert(c, icmd.Expected{
Out: fmt.Sprintf("FROM %s@sha", repoName[:len(repoName)-7]),
})
// We should also have a tag reference for the image.
dockerCmd(c, "inspect", repoName)
// We should now be able to remove the tag reference.
dockerCmd(c, "rmi", repoName)
}
func (s *DockerTrustSuite) TestTrustedBuildUntrustedTag(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/build-untrusted-tag:latest", privateRegistryURL)
dockerFile := fmt.Sprintf(`
FROM %s
RUN []
`, repoName)
name := "testtrustedbuilduntrustedtag"
buildImage(name, trustedBuild, build.WithDockerfile(dockerFile)).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "does not have trust data for",
})
}
// FIXME(vdemeester) should migrate to docker/cli e2e tests
func (s *DockerTrustSuite) TestBuildContextDirIsSymlink(c *check.C) {
testRequires(c, DaemonIsLinux)
tempDir, err := ioutil.TempDir("", "test-build-dir-is-symlink-")
c.Assert(err, check.IsNil)
defer os.RemoveAll(tempDir)
// Make a real context directory in this temp directory with a simple
// Dockerfile.
realContextDirname := filepath.Join(tempDir, "context")
if err := os.Mkdir(realContextDirname, os.FileMode(0755)); err != nil {
c.Fatal(err)
}
if err = ioutil.WriteFile(
filepath.Join(realContextDirname, "Dockerfile"),
[]byte(`
FROM busybox
RUN echo hello world
`),
os.FileMode(0644),
); err != nil {
c.Fatal(err)
}
// Make a symlink to the real context directory.
contextSymlinkName := filepath.Join(tempDir, "context_link")
if err := os.Symlink(realContextDirname, contextSymlinkName); err != nil {
c.Fatal(err)
}
// Executing the build with the symlink as the specified context should
// *not* fail.
dockerCmd(c, "build", contextSymlinkName)
}
func (s *DockerTrustSuite) TestTrustedBuildTagFromReleasesRole(c *check.C) {
testRequires(c, NotaryHosting)
latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
repoName := strings.TrimSuffix(latestTag, ":latest")
// Now create the releases role
s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
s.notaryPublish(c, repoName)
// push a different tag to the releases role
otherTag := fmt.Sprintf("%s:other", repoName)
cli.DockerCmd(c, "tag", "busybox", otherTag)
cli.Docker(cli.Args("push", otherTag), trustedCmd).Assert(c, icmd.Success)
s.assertTargetInRoles(c, repoName, "other", "targets/releases")
s.assertTargetNotInRoles(c, repoName, "other", "targets")
cli.DockerCmd(c, "rmi", otherTag)
dockerFile := fmt.Sprintf(`
FROM %s
RUN []
`, otherTag)
name := "testtrustedbuildreleasesrole"
cli.BuildCmd(c, name, trustedCmd, build.WithDockerfile(dockerFile)).Assert(c, icmd.Expected{
Out: fmt.Sprintf("FROM %s@sha", repoName),
})
}
func (s *DockerTrustSuite) TestTrustedBuildTagIgnoresOtherDelegationRoles(c *check.C) {
testRequires(c, NotaryHosting)
latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
repoName := strings.TrimSuffix(latestTag, ":latest")
// Now create a non-releases delegation role
s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[0].Public)
s.notaryImportKey(c, repoName, "targets/other", s.not.keys[0].Private)
s.notaryPublish(c, repoName)
// push a different tag to the other role
otherTag := fmt.Sprintf("%s:other", repoName)
cli.DockerCmd(c, "tag", "busybox", otherTag)
cli.Docker(cli.Args("push", otherTag), trustedCmd).Assert(c, icmd.Success)
s.assertTargetInRoles(c, repoName, "other", "targets/other")
s.assertTargetNotInRoles(c, repoName, "other", "targets")
cli.DockerCmd(c, "rmi", otherTag)
dockerFile := fmt.Sprintf(`
FROM %s
RUN []
`, otherTag)
name := "testtrustedbuildotherrole"
cli.Docker(cli.Build(name), trustedCmd, build.WithDockerfile(dockerFile)).Assert(c, icmd.Expected{
ExitCode: 1,
})
}
// Issue #15634: COPY fails when path starts with "null"
func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
name := "testbuildnullstringinaddcopyvolume"
@@ -6018,28 +5884,6 @@ func (s *DockerSuite) TestBuildMultiStageNameVariants(c *check.C) {
cli.Docker(cli.Args("run", "build1", "cat", "f2")).Assert(c, icmd.Expected{Out: "bar2"})
}
func (s *DockerTrustSuite) TestBuildMultiStageTrusted(c *check.C) {
img1 := s.setupTrustedImage(c, "trusted-build1")
img2 := s.setupTrustedImage(c, "trusted-build2")
dockerFile := fmt.Sprintf(`
FROM %s AS build-base
RUN echo ok > /foo
FROM %s
COPY --from=build-base foo bar`, img1, img2)
name := "testcopyfromtrustedbuild"
r := buildImage(name, trustedBuild, build.WithDockerfile(dockerFile))
r.Assert(c, icmd.Expected{
Out: fmt.Sprintf("FROM %s@sha", img1[:len(img1)-7]),
})
r.Assert(c, icmd.Expected{
Out: fmt.Sprintf("FROM %s@sha", img2[:len(img2)-7]),
})
dockerCmdWithResult("run", name, "cat", "bar").Assert(c, icmd.Expected{Out: "ok"})
}
func (s *DockerSuite) TestBuildMultiStageMultipleBuildsWindows(c *check.C) {
testRequires(c, DaemonIsWindows)
dockerfile := `
@@ -3,7 +3,6 @@ package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"reflect"
"strings"
@@ -16,7 +15,6 @@ import (
"github.com/docker/docker/pkg/stringid"
"github.com/docker/go-connections/nat"
"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/icmd"
)
// Make sure we can create a simple container with some args
@@ -292,75 +290,6 @@ func (s *DockerSuite) TestCreateByImageID(c *check.C) {
}
}
func (s *DockerTrustSuite) TestTrustedCreate(c *check.C) {
repoName := s.setupTrustedImage(c, "trusted-create")
// Try create
cli.Docker(cli.Args("create", repoName), trustedCmd).Assert(c, SuccessTagging)
cli.DockerCmd(c, "rmi", repoName)
// Try untrusted create to ensure we pushed the tag to the registry
cli.Docker(cli.Args("create", "--disable-content-trust=true", repoName)).Assert(c, SuccessDownloadedOnStderr)
}
func (s *DockerTrustSuite) TestUntrustedCreate(c *check.C) {
repoName := fmt.Sprintf("%v/dockercliuntrusted/createtest", privateRegistryURL)
withTagName := fmt.Sprintf("%s:latest", repoName)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", withTagName)
cli.DockerCmd(c, "push", withTagName)
cli.DockerCmd(c, "rmi", withTagName)
// Try trusted create on untrusted tag
cli.Docker(cli.Args("create", withTagName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 1,
Err: fmt.Sprintf("does not have trust data for %s", repoName),
})
}
func (s *DockerTrustSuite) TestTrustedIsolatedCreate(c *check.C) {
repoName := s.setupTrustedImage(c, "trusted-isolated-create")
// Try create
cli.Docker(cli.Args("--config", "/tmp/docker-isolated-create", "create", repoName), trustedCmd).Assert(c, SuccessTagging)
defer os.RemoveAll("/tmp/docker-isolated-create")
cli.DockerCmd(c, "rmi", repoName)
}
func (s *DockerTrustSuite) TestTrustedCreateFromBadTrustServer(c *check.C) {
repoName := fmt.Sprintf("%v/dockerclievilcreate/trusted:latest", privateRegistryURL)
evilLocalConfigDir, err := ioutil.TempDir("", "evilcreate-local-config-dir")
c.Assert(err, check.IsNil)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
cli.DockerCmd(c, "rmi", repoName)
// Try create
cli.Docker(cli.Args("create", repoName), trustedCmd).Assert(c, SuccessTagging)
cli.DockerCmd(c, "rmi", repoName)
// Kill the notary server, start a new "evil" one.
s.not.Close()
s.not, err = newTestNotary(c)
c.Assert(err, check.IsNil)
// In order to make an evil server, lets re-init a client (with a different trust dir) and push new data.
// tag an image and upload it to the private registry
cli.DockerCmd(c, "--config", evilLocalConfigDir, "tag", "busybox", repoName)
// Push up to the new server
cli.Docker(cli.Args("--config", evilLocalConfigDir, "push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
// Now, try creating with the original client from this new trust server. This should fail because the new root is invalid.
cli.Docker(cli.Args("create", repoName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "could not rotate trust to a new trusted root",
})
}
func (s *DockerSuite) TestCreateStopSignal(c *check.C) {
name := "test_create_stop_signal"
dockerCmd(c, "create", "--name", name, "--stop-signal", "9", "busybox")
@@ -16,7 +16,6 @@ import (
"github.com/docker/docker/integration-cli/daemon"
"github.com/docker/docker/integration-cli/fixtures/plugin"
"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/icmd"
"golang.org/x/net/context"
)
@@ -352,51 +351,6 @@ func (s *DockerSuite) TestPluginInspectOnWindows(c *check.C) {
c.Assert(err.Error(), checker.Contains, "plugins are not supported on this platform")
}
func (s *DockerTrustSuite) TestPluginTrustedInstall(c *check.C) {
testRequires(c, DaemonIsLinux, IsAmd64, Network)
trustedName := s.setupTrustedplugin(c, pNameWithTag, "trusted-plugin-install")
cli.Docker(cli.Args("plugin", "install", "--grant-all-permissions", trustedName), trustedCmd).Assert(c, icmd.Expected{
Out: trustedName,
})
out := cli.DockerCmd(c, "plugin", "ls").Combined()
c.Assert(out, checker.Contains, "true")
out = cli.DockerCmd(c, "plugin", "disable", trustedName).Combined()
c.Assert(strings.TrimSpace(out), checker.Contains, trustedName)
out = cli.DockerCmd(c, "plugin", "enable", trustedName).Combined()
c.Assert(strings.TrimSpace(out), checker.Contains, trustedName)
out = cli.DockerCmd(c, "plugin", "rm", "-f", trustedName).Combined()
c.Assert(strings.TrimSpace(out), checker.Contains, trustedName)
// Try untrusted pull to ensure we pushed the tag to the registry
cli.Docker(cli.Args("plugin", "install", "--disable-content-trust=true", "--grant-all-permissions", trustedName), trustedCmd).Assert(c, SuccessDownloaded)
out = cli.DockerCmd(c, "plugin", "ls").Combined()
c.Assert(out, checker.Contains, "true")
}
func (s *DockerTrustSuite) TestPluginUntrustedInstall(c *check.C) {
testRequires(c, DaemonIsLinux, IsAmd64, Network)
pluginName := fmt.Sprintf("%v/dockercliuntrusted/plugintest:latest", privateRegistryURL)
// install locally and push to private registry
cli.DockerCmd(c, "plugin", "install", "--grant-all-permissions", "--alias", pluginName, pNameWithTag)
cli.DockerCmd(c, "plugin", "push", pluginName)
cli.DockerCmd(c, "plugin", "rm", "-f", pluginName)
// Try trusted install on untrusted plugin
cli.Docker(cli.Args("plugin", "install", "--grant-all-permissions", pluginName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "Error: remote trust data does not exist",
})
}
func (ps *DockerPluginSuite) TestPluginIDPrefix(c *check.C) {
name := "test"
client := testEnv.APIClient()
@@ -1,222 +0,0 @@
package main
import (
"fmt"
"io/ioutil"
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/integration-cli/cli"
"github.com/docker/docker/integration-cli/cli/build"
"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/icmd"
)
func (s *DockerTrustSuite) TestTrustedPull(c *check.C) {
repoName := s.setupTrustedImage(c, "trusted-pull")
// Try pull
cli.Docker(cli.Args("pull", repoName), trustedCmd).Assert(c, SuccessTagging)
cli.DockerCmd(c, "rmi", repoName)
// Try untrusted pull to ensure we pushed the tag to the registry
cli.Docker(cli.Args("pull", "--disable-content-trust=true", repoName), trustedCmd).Assert(c, SuccessDownloaded)
}
func (s *DockerTrustSuite) TestTrustedIsolatedPull(c *check.C) {
repoName := s.setupTrustedImage(c, "trusted-isolated-pull")
// Try pull (run from isolated directory without trust information)
cli.Docker(cli.Args("--config", "/tmp/docker-isolated", "pull", repoName), trustedCmd).Assert(c, SuccessTagging)
cli.DockerCmd(c, "rmi", repoName)
}
func (s *DockerTrustSuite) TestUntrustedPull(c *check.C) {
repoName := fmt.Sprintf("%v/dockercliuntrusted/pulltest:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.DockerCmd(c, "push", repoName)
cli.DockerCmd(c, "rmi", repoName)
// Try trusted pull on untrusted tag
cli.Docker(cli.Args("pull", repoName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "Error: remote trust data does not exist",
})
}
func (s *DockerTrustSuite) TestTrustedPullFromBadTrustServer(c *check.C) {
repoName := fmt.Sprintf("%v/dockerclievilpull/trusted:latest", privateRegistryURL)
evilLocalConfigDir, err := ioutil.TempDir("", "evil-local-config-dir")
if err != nil {
c.Fatalf("Failed to create local temp dir")
}
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
cli.DockerCmd(c, "rmi", repoName)
// Try pull
cli.Docker(cli.Args("pull", repoName), trustedCmd).Assert(c, SuccessTagging)
cli.DockerCmd(c, "rmi", repoName)
// Kill the notary server, start a new "evil" one.
s.not.Close()
s.not, err = newTestNotary(c)
c.Assert(err, check.IsNil, check.Commentf("Restarting notary server failed."))
// In order to make an evil server, lets re-init a client (with a different trust dir) and push new data.
// tag an image and upload it to the private registry
cli.DockerCmd(c, "--config", evilLocalConfigDir, "tag", "busybox", repoName)
// Push up to the new server
cli.Docker(cli.Args("--config", evilLocalConfigDir, "push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
// Now, try pulling with the original client from this new trust server. This should fail because the new root is invalid.
cli.Docker(cli.Args("pull", repoName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "could not rotate trust to a new trusted root",
})
}
func (s *DockerTrustSuite) TestTrustedOfflinePull(c *check.C) {
repoName := s.setupTrustedImage(c, "trusted-offline-pull")
cli.Docker(cli.Args("pull", repoName), trustedCmdWithServer("https://invalidnotaryserver")).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "error contacting notary server",
})
// Do valid trusted pull to warm cache
cli.Docker(cli.Args("pull", repoName), trustedCmd).Assert(c, SuccessTagging)
cli.DockerCmd(c, "rmi", repoName)
// Try pull again with invalid notary server, should use cache
cli.Docker(cli.Args("pull", repoName), trustedCmdWithServer("https://invalidnotaryserver")).Assert(c, SuccessTagging)
}
func (s *DockerTrustSuite) TestTrustedPullDelete(c *check.C) {
repoName := fmt.Sprintf("%v/dockercli/%s:latest", privateRegistryURL, "trusted-pull-delete")
// tag the image and upload it to the private registry
cli.BuildCmd(c, repoName, build.WithDockerfile(`
FROM busybox
CMD echo trustedpulldelete
`))
cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
cli.DockerCmd(c, "rmi", repoName)
// Try pull
result := cli.Docker(cli.Args("pull", repoName), trustedCmd).Assert(c, icmd.Success)
matches := digestRegex.FindStringSubmatch(result.Combined())
c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from pull output: %s", result.Combined()))
pullDigest := matches[1]
imageID := inspectField(c, repoName, "Id")
imageByDigest := repoName + "@" + pullDigest
byDigestID := inspectField(c, imageByDigest, "Id")
c.Assert(byDigestID, checker.Equals, imageID)
// rmi of tag should also remove the digest reference
cli.DockerCmd(c, "rmi", repoName)
_, err := inspectFieldWithError(imageByDigest, "Id")
c.Assert(err, checker.NotNil, check.Commentf("digest reference should have been removed"))
_, err = inspectFieldWithError(imageID, "Id")
c.Assert(err, checker.NotNil, check.Commentf("image should have been deleted"))
}
func (s *DockerTrustSuite) TestTrustedPullReadsFromReleasesRole(c *check.C) {
testRequires(c, NotaryHosting)
repoName := fmt.Sprintf("%v/dockerclireleasesdelegationpulling/trusted", privateRegistryURL)
targetName := fmt.Sprintf("%s:latest", repoName)
// Push with targets first, initializing the repo
cli.DockerCmd(c, "tag", "busybox", targetName)
cli.Docker(cli.Args("push", targetName), trustedCmd).Assert(c, icmd.Success)
s.assertTargetInRoles(c, repoName, "latest", "targets")
// Try pull, check we retrieve from targets role
cli.Docker(cli.Args("-D", "pull", repoName), trustedCmd).Assert(c, icmd.Expected{
Err: "retrieving target for targets role",
})
// Now we'll create the releases role, and try pushing and pulling
s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
s.notaryPublish(c, repoName)
// try a pull, check that we can still pull because we can still read the
// old tag in the targets role
cli.Docker(cli.Args("-D", "pull", repoName), trustedCmd).Assert(c, icmd.Expected{
Err: "retrieving target for targets role",
})
// try a pull -a, check that it succeeds because we can still pull from the
// targets role
cli.Docker(cli.Args("-D", "pull", "-a", repoName), trustedCmd).Assert(c, icmd.Success)
// Push, should sign with targets/releases
cli.DockerCmd(c, "tag", "busybox", targetName)
cli.Docker(cli.Args("push", targetName), trustedCmd).Assert(c, icmd.Success)
s.assertTargetInRoles(c, repoName, "latest", "targets", "targets/releases")
// Try pull, check we retrieve from targets/releases role
cli.Docker(cli.Args("-D", "pull", repoName), trustedCmd).Assert(c, icmd.Expected{
Err: "retrieving target for targets/releases role",
})
// Create another delegation that we'll sign with
s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[1].Public)
s.notaryImportKey(c, repoName, "targets/other", s.not.keys[1].Private)
s.notaryPublish(c, repoName)
cli.DockerCmd(c, "tag", "busybox", targetName)
cli.Docker(cli.Args("push", targetName), trustedCmd).Assert(c, icmd.Success)
s.assertTargetInRoles(c, repoName, "latest", "targets", "targets/releases", "targets/other")
// Try pull, check we retrieve from targets/releases role
cli.Docker(cli.Args("-D", "pull", repoName), trustedCmd).Assert(c, icmd.Expected{
Err: "retrieving target for targets/releases role",
})
}
func (s *DockerTrustSuite) TestTrustedPullIgnoresOtherDelegationRoles(c *check.C) {
testRequires(c, NotaryHosting)
repoName := fmt.Sprintf("%v/dockerclipullotherdelegation/trusted", privateRegistryURL)
targetName := fmt.Sprintf("%s:latest", repoName)
// We'll create a repo first with a non-release delegation role, so that when we
// push we'll sign it into the delegation role
s.notaryInitRepo(c, repoName)
s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[0].Public)
s.notaryImportKey(c, repoName, "targets/other", s.not.keys[0].Private)
s.notaryPublish(c, repoName)
// Push should write to the delegation role, not targets
cli.DockerCmd(c, "tag", "busybox", targetName)
cli.Docker(cli.Args("push", targetName), trustedCmd).Assert(c, icmd.Success)
s.assertTargetInRoles(c, repoName, "latest", "targets/other")
s.assertTargetNotInRoles(c, repoName, "latest", "targets")
// Try pull - we should fail, since pull will only pull from the targets/releases
// role or the targets role
cli.DockerCmd(c, "tag", "busybox", targetName)
cli.Docker(cli.Args("-D", "pull", repoName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "No trust data for",
})
// try a pull -a: we should fail since pull will only pull from the targets/releases
// role or the targets role
cli.Docker(cli.Args("-D", "pull", "-a", repoName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "No trusted tags for",
})
}
@@ -7,14 +7,11 @@ import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"sync"
"github.com/docker/distribution/reference"
"github.com/docker/docker/cli/config"
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/integration-cli/cli"
"github.com/docker/docker/integration-cli/cli/build"
"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/icmd"
@@ -281,225 +278,6 @@ func (s *DockerSchema1RegistrySuite) TestCrossRepositoryLayerPushNotSupported(c
c.Assert(out3, check.Equals, "hello world")
}
func (s *DockerTrustSuite) TestTrustedPush(c *check.C) {
repoName := fmt.Sprintf("%v/dockerclitrusted/pushtest:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
// Try pull after push
cli.Docker(cli.Args("pull", repoName), trustedCmd).Assert(c, icmd.Expected{
Out: "Status: Image is up to date",
})
// Assert that we rotated the snapshot key to the server by checking our local keystore
contents, err := ioutil.ReadDir(filepath.Join(config.Dir(), "trust/private/tuf_keys", privateRegistryURL, "dockerclitrusted/pushtest"))
c.Assert(err, check.IsNil, check.Commentf("Unable to read local tuf key files"))
// Check that we only have 1 key (targets key)
c.Assert(contents, checker.HasLen, 1)
}
func (s *DockerTrustSuite) TestTrustedPushWithEnvPasswords(c *check.C) {
repoName := fmt.Sprintf("%v/dockerclienv/trusted:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.Docker(cli.Args("push", repoName), trustedCmdWithPassphrases("12345678", "12345678")).Assert(c, SuccessSigningAndPushing)
// Try pull after push
cli.Docker(cli.Args("pull", repoName), trustedCmd).Assert(c, icmd.Expected{
Out: "Status: Image is up to date",
})
}
func (s *DockerTrustSuite) TestTrustedPushWithFailingServer(c *check.C) {
repoName := fmt.Sprintf("%v/dockerclitrusted/failingserver:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
// Using a name that doesn't resolve to an address makes this test faster
cli.Docker(cli.Args("push", repoName), trustedCmdWithServer("https://server.invalid:81/")).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "error contacting notary server",
})
}
func (s *DockerTrustSuite) TestTrustedPushWithoutServerAndUntrusted(c *check.C) {
repoName := fmt.Sprintf("%v/dockerclitrusted/trustedandnot:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
result := cli.Docker(cli.Args("push", "--disable-content-trust", repoName), trustedCmdWithServer("https://server.invalid:81/"))
result.Assert(c, icmd.Success)
c.Assert(result.Combined(), check.Not(checker.Contains), "Error establishing connection to notary repository", check.Commentf("Missing expected output on trusted push with --disable-content-trust:"))
}
func (s *DockerTrustSuite) TestTrustedPushWithExistingTag(c *check.C) {
repoName := fmt.Sprintf("%v/dockerclitag/trusted:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.DockerCmd(c, "push", repoName)
cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
// Try pull after push
cli.Docker(cli.Args("pull", repoName), trustedCmd).Assert(c, icmd.Expected{
Out: "Status: Image is up to date",
})
}
func (s *DockerTrustSuite) TestTrustedPushWithExistingSignedTag(c *check.C) {
repoName := fmt.Sprintf("%v/dockerclipushpush/trusted:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
// Do a trusted push
cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
// Do another trusted push
cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
cli.DockerCmd(c, "rmi", repoName)
// Try pull to ensure the double push did not break our ability to pull
cli.Docker(cli.Args("pull", repoName), trustedCmd).Assert(c, SuccessDownloaded)
}
func (s *DockerTrustSuite) TestTrustedPushWithIncorrectPassphraseForNonRoot(c *check.C) {
repoName := fmt.Sprintf("%v/dockercliincorretpwd/trusted:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
// Push with default passphrases
cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
// Push with wrong passphrases
cli.Docker(cli.Args("push", repoName), trustedCmdWithPassphrases("12345678", "87654321")).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "could not find necessary signing keys",
})
}
func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C) {
testRequires(c, NotaryHosting)
repoName := fmt.Sprintf("%v/dockerclireleasedelegationinitfirst/trusted", privateRegistryURL)
targetName := fmt.Sprintf("%s:latest", repoName)
s.notaryInitRepo(c, repoName)
s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
s.notaryPublish(c, repoName)
s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", targetName)
cli.Docker(cli.Args("push", targetName), trustedCmd).Assert(c, SuccessSigningAndPushing)
// check to make sure that the target has been added to targets/releases and not targets
s.assertTargetInRoles(c, repoName, "latest", "targets/releases")
s.assertTargetNotInRoles(c, repoName, "latest", "targets")
// Try pull after push
os.RemoveAll(filepath.Join(config.Dir(), "trust"))
cli.Docker(cli.Args("pull", targetName), trustedCmd).Assert(c, icmd.Expected{
Out: "Status: Image is up to date",
})
}
func (s *DockerTrustSuite) TestTrustedPushSignsAllFirstLevelRolesWeHaveKeysFor(c *check.C) {
testRequires(c, NotaryHosting)
repoName := fmt.Sprintf("%v/dockerclimanyroles/trusted", privateRegistryURL)
targetName := fmt.Sprintf("%s:latest", repoName)
s.notaryInitRepo(c, repoName)
s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public)
s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public)
// import everything except the third key
s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
s.notaryCreateDelegation(c, repoName, "targets/role1/subrole", s.not.keys[3].Public)
s.notaryImportKey(c, repoName, "targets/role1/subrole", s.not.keys[3].Private)
s.notaryPublish(c, repoName)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", targetName)
cli.Docker(cli.Args("push", targetName), trustedCmd).Assert(c, SuccessSigningAndPushing)
// check to make sure that the target has been added to targets/role1 and targets/role2, and
// not targets (because there are delegations) or targets/role3 (due to missing key) or
// targets/role1/subrole (due to it being a second level delegation)
s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role2")
s.assertTargetNotInRoles(c, repoName, "latest", "targets")
// Try pull after push
os.RemoveAll(filepath.Join(config.Dir(), "trust"))
// pull should fail because none of these are the releases role
cli.Docker(cli.Args("pull", targetName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 1,
})
}
func (s *DockerTrustSuite) TestTrustedPushSignsForRolesWithKeysAndValidPaths(c *check.C) {
repoName := fmt.Sprintf("%v/dockerclirolesbykeysandpaths/trusted", privateRegistryURL)
targetName := fmt.Sprintf("%s:latest", repoName)
s.notaryInitRepo(c, repoName)
s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public, "l", "z")
s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public, "x", "y")
s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public, "latest")
s.notaryCreateDelegation(c, repoName, "targets/role4", s.not.keys[3].Public, "latest")
// import everything except the third key
s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
s.notaryImportKey(c, repoName, "targets/role4", s.not.keys[3].Private)
s.notaryPublish(c, repoName)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", targetName)
cli.Docker(cli.Args("push", targetName), trustedCmd).Assert(c, SuccessSigningAndPushing)
// check to make sure that the target has been added to targets/role1 and targets/role4, and
// not targets (because there are delegations) or targets/role2 (due to path restrictions) or
// targets/role3 (due to missing key)
s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role4")
s.assertTargetNotInRoles(c, repoName, "latest", "targets")
// Try pull after push
os.RemoveAll(filepath.Join(config.Dir(), "trust"))
// pull should fail because none of these are the releases role
cli.Docker(cli.Args("pull", targetName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 1,
})
}
func (s *DockerTrustSuite) TestTrustedPushDoesntSignTargetsIfDelegationsExist(c *check.C) {
testRequires(c, NotaryHosting)
repoName := fmt.Sprintf("%v/dockerclireleasedelegationnotsignable/trusted", privateRegistryURL)
targetName := fmt.Sprintf("%s:latest", repoName)
s.notaryInitRepo(c, repoName)
s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
s.notaryPublish(c, repoName)
// do not import any delegations key
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", targetName)
cli.Docker(cli.Args("push", targetName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "no valid signing keys",
})
s.assertTargetNotInRoles(c, repoName, "latest", "targets", "targets/role1")
}
func (s *DockerRegistryAuthHtpasswdSuite) TestPushNoCredentialsNoRetry(c *check.C) {
repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
dockerCmd(c, "tag", "busybox", repoName)
@@ -3140,75 +3140,6 @@ func (s *DockerSuite) TestRunNetworkFilesBindMountROFilesystem(c *check.C) {
}
}
func (s *DockerTrustSuite) TestTrustedRun(c *check.C) {
// Windows does not support this functionality
testRequires(c, DaemonIsLinux)
repoName := s.setupTrustedImage(c, "trusted-run")
// Try run
cli.Docker(cli.Args("run", repoName), trustedCmd).Assert(c, SuccessTagging)
cli.DockerCmd(c, "rmi", repoName)
// Try untrusted run to ensure we pushed the tag to the registry
cli.Docker(cli.Args("run", "--disable-content-trust=true", repoName), trustedCmd).Assert(c, SuccessDownloadedOnStderr)
}
func (s *DockerTrustSuite) TestUntrustedRun(c *check.C) {
// Windows does not support this functionality
testRequires(c, DaemonIsLinux)
repoName := fmt.Sprintf("%v/dockercliuntrusted/runtest:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.DockerCmd(c, "push", repoName)
cli.DockerCmd(c, "rmi", repoName)
// Try trusted run on untrusted tag
cli.Docker(cli.Args("run", repoName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 125,
Err: "does not have trust data for",
})
}
func (s *DockerTrustSuite) TestTrustedRunFromBadTrustServer(c *check.C) {
// Windows does not support this functionality
testRequires(c, DaemonIsLinux)
repoName := fmt.Sprintf("%v/dockerclievilrun/trusted:latest", privateRegistryURL)
evilLocalConfigDir, err := ioutil.TempDir("", "evilrun-local-config-dir")
if err != nil {
c.Fatalf("Failed to create local temp dir")
}
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
cli.DockerCmd(c, "rmi", repoName)
// Try run
cli.Docker(cli.Args("run", repoName), trustedCmd).Assert(c, SuccessTagging)
cli.DockerCmd(c, "rmi", repoName)
// Kill the notary server, start a new "evil" one.
s.not.Close()
s.not, err = newTestNotary(c)
if err != nil {
c.Fatalf("Restarting notary server failed.")
}
// In order to make an evil server, lets re-init a client (with a different trust dir) and push new data.
// tag an image and upload it to the private registry
cli.DockerCmd(c, "--config", evilLocalConfigDir, "tag", "busybox", repoName)
// Push up to the new server
cli.Docker(cli.Args("--config", evilLocalConfigDir, "push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
// Now, try running with the original client from this new trust server. This should fail because the new root is invalid.
cli.Docker(cli.Args("run", repoName), trustedCmd).Assert(c, icmd.Expected{
ExitCode: 125,
Err: "could not rotate trust to a new trusted root",
})
}
func (s *DockerSuite) TestPtraceContainerProcsFromHost(c *check.C) {
// Not applicable on Windows as uses Unix specific functionality
testRequires(c, DaemonIsLinux, SameHostDaemon)
@@ -1560,78 +1560,6 @@ func (s *DockerSwarmSuite) TestSwarmNetworkIPAMOptions(c *check.C) {
c.Assert(strings.TrimSpace(out), checker.Contains, "com.docker.network.ipam.serial:true")
}
func (s *DockerTrustedSwarmSuite) TestTrustedServiceCreate(c *check.C) {
d := s.swarmSuite.AddDaemon(c, true, true)
// Attempt creating a service from an image that is known to notary.
repoName := s.trustSuite.setupTrustedImage(c, "trusted-pull")
name := "trusted"
cli.Docker(cli.Args("-D", "service", "create", "--detach", "--no-resolve-image", "--name", name, repoName, "top"), trustedCmd, cli.Daemon(d.Daemon)).Assert(c, icmd.Expected{
Err: "resolved image tag to",
})
out, err := d.Cmd("service", "inspect", "--pretty", name)
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(out, checker.Contains, repoName+"@", check.Commentf(out))
// Try trusted service create on an untrusted tag.
repoName = fmt.Sprintf("%v/untrustedservicecreate/createtest:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.DockerCmd(c, "push", repoName)
cli.DockerCmd(c, "rmi", repoName)
name = "untrusted"
cli.Docker(cli.Args("service", "create", "--detach", "--no-resolve-image", "--name", name, repoName, "top"), trustedCmd, cli.Daemon(d.Daemon)).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "Error: remote trust data does not exist",
})
out, err = d.Cmd("service", "inspect", "--pretty", name)
c.Assert(err, checker.NotNil, check.Commentf(out))
}
func (s *DockerTrustedSwarmSuite) TestTrustedServiceUpdate(c *check.C) {
d := s.swarmSuite.AddDaemon(c, true, true)
// Attempt creating a service from an image that is known to notary.
repoName := s.trustSuite.setupTrustedImage(c, "trusted-pull")
name := "myservice"
// Create a service without content trust
cli.Docker(cli.Args("service", "create", "--detach", "--no-resolve-image", "--name", name, repoName, "top"), cli.Daemon(d.Daemon)).Assert(c, icmd.Success)
result := cli.Docker(cli.Args("service", "inspect", "--pretty", name), cli.Daemon(d.Daemon))
c.Assert(result.Error, checker.IsNil, check.Commentf(result.Combined()))
// Daemon won't insert the digest because this is disabled by
// DOCKER_SERVICE_PREFER_OFFLINE_IMAGE.
c.Assert(result.Combined(), check.Not(checker.Contains), repoName+"@", check.Commentf(result.Combined()))
cli.Docker(cli.Args("-D", "service", "update", "--detach", "--no-resolve-image", "--image", repoName, name), trustedCmd, cli.Daemon(d.Daemon)).Assert(c, icmd.Expected{
Err: "resolved image tag to",
})
cli.Docker(cli.Args("service", "inspect", "--pretty", name), cli.Daemon(d.Daemon)).Assert(c, icmd.Expected{
Out: repoName + "@",
})
// Try trusted service update on an untrusted tag.
repoName = fmt.Sprintf("%v/untrustedservicecreate/createtest:latest", privateRegistryURL)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.DockerCmd(c, "push", repoName)
cli.DockerCmd(c, "rmi", repoName)
cli.Docker(cli.Args("service", "update", "--detach", "--no-resolve-image", "--image", repoName, name), trustedCmd, cli.Daemon(d.Daemon)).Assert(c, icmd.Expected{
ExitCode: 1,
Err: "Error: remote trust data does not exist",
})
}
// Test case for issue #27866, which did not allow NW name that is the prefix of a swarm NW ID.
// e.g. if the ingress ID starts with "n1", it was impossible to create a NW named "n1".
func (s *DockerSwarmSuite) TestSwarmNetworkCreateIssue27866(c *check.C) {
@@ -202,12 +202,6 @@ func buildImage(name string, cmdOperators ...cli.CmdOperator) *icmd.Result {
return cli.Docker(cli.Build(name), cmdOperators...)
}
// Deprecated: use trustedcmd
func trustedBuild(cmd *icmd.Cmd) func() {
trustedCmd(cmd)
return nil
}
// Write `content` to the file at path `dst`, creating it if necessary,
// as well as any missing directories.
// The file is truncated if it already exists.
@@ -306,13 +300,6 @@ func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *registry.V2
return reg
}
func setupNotary(c *check.C) *testNotary {
ts, err := newTestNotary(c)
c.Assert(err, check.IsNil)
return ts
}
// appendBaseEnv appends the minimum set of environment variables to exec the
// docker cli binary for testing with correct configuration to the given env
// list.
@@ -112,22 +112,6 @@ func Apparmor() bool {
return err == nil && len(buf) > 1 && buf[0] == 'Y'
}
func NotaryHosting() bool {
// for now notary binary is built only if we're running inside
// container through `make test`. Figure that out by testing if
// notary-server binary is in PATH.
_, err := exec.LookPath(notaryServerBinary)
return err == nil
}
func NotaryServerHosting() bool {
// for now notary-server binary is built only if we're running inside
// container through `make test`. Figure that out by testing if
// notary-server binary is in PATH.
_, err := exec.LookPath(notaryServerBinary)
return err == nil
}
func Devicemapper() bool {
return strings.HasPrefix(testEnv.DaemonInfo.Driver, "devicemapper")
}
@@ -1,334 +0,0 @@
package main
import (
"context"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/docker/docker/api/types"
cliconfig "github.com/docker/docker/cli/config"
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/integration-cli/cli"
"github.com/docker/docker/integration-cli/fixtures/plugin"
"github.com/docker/go-connections/tlsconfig"
"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/icmd"
)
var notaryBinary = "notary"
var notaryServerBinary = "notary-server"
type keyPair struct {
Public string
Private string
}
type testNotary struct {
cmd *exec.Cmd
dir string
keys []keyPair
}
const notaryHost = "localhost:4443"
const notaryURL = "https://" + notaryHost
var SuccessTagging = icmd.Expected{
Out: "Tagging",
}
var SuccessSigningAndPushing = icmd.Expected{
Out: "Signing and pushing trust metadata",
}
var SuccessDownloaded = icmd.Expected{
Out: "Status: Downloaded",
}
var SuccessDownloadedOnStderr = icmd.Expected{
Err: "Status: Downloaded",
}
func newTestNotary(c *check.C) (*testNotary, error) {
// generate server config
template := `{
"server": {
"http_addr": "%s",
"tls_key_file": "%s",
"tls_cert_file": "%s"
},
"trust_service": {
"type": "local",
"hostname": "",
"port": "",
"key_algorithm": "ed25519"
},
"logging": {
"level": "debug"
},
"storage": {
"backend": "memory"
}
}`
tmp, err := ioutil.TempDir("", "notary-test-")
if err != nil {
return nil, err
}
confPath := filepath.Join(tmp, "config.json")
config, err := os.Create(confPath)
if err != nil {
return nil, err
}
defer config.Close()
workingDir, err := os.Getwd()
if err != nil {
return nil, err
}
if _, err := fmt.Fprintf(config, template, notaryHost, filepath.Join(workingDir, "fixtures/notary/localhost.key"), filepath.Join(workingDir, "fixtures/notary/localhost.cert")); err != nil {
os.RemoveAll(tmp)
return nil, err
}
// generate client config
clientConfPath := filepath.Join(tmp, "client-config.json")
clientConfig, err := os.Create(clientConfPath)
if err != nil {
return nil, err
}
defer clientConfig.Close()
template = `{
"trust_dir" : "%s",
"remote_server": {
"url": "%s",
"skipTLSVerify": true
}
}`
if _, err = fmt.Fprintf(clientConfig, template, filepath.Join(cliconfig.Dir(), "trust"), notaryURL); err != nil {
os.RemoveAll(tmp)
return nil, err
}
// load key fixture filenames
var keys []keyPair
for i := 1; i < 5; i++ {
keys = append(keys, keyPair{
Public: filepath.Join(workingDir, fmt.Sprintf("fixtures/notary/delgkey%v.crt", i)),
Private: filepath.Join(workingDir, fmt.Sprintf("fixtures/notary/delgkey%v.key", i)),
})
}
// run notary-server
cmd := exec.Command(notaryServerBinary, "-config", confPath)
if err := cmd.Start(); err != nil {
os.RemoveAll(tmp)
if os.IsNotExist(err) {
c.Skip(err.Error())
}
return nil, err
}
testNotary := &testNotary{
cmd: cmd,
dir: tmp,
keys: keys,
}
// Wait for notary to be ready to serve requests.
for i := 1; i <= 20; i++ {
if err = testNotary.Ping(); err == nil {
break
}
time.Sleep(10 * time.Millisecond * time.Duration(i*i))
}
if err != nil {
c.Fatalf("Timeout waiting for test notary to become available: %s", err)
}
return testNotary, nil
}
func (t *testNotary) Ping() error {
tlsConfig := tlsconfig.ClientDefault()
tlsConfig.InsecureSkipVerify = true
client := http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
TLSHandshakeTimeout: 10 * time.Second,
TLSClientConfig: tlsConfig,
},
}
resp, err := client.Get(fmt.Sprintf("%s/v2/", notaryURL))
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("notary ping replied with an unexpected status code %d", resp.StatusCode)
}
return nil
}
func (t *testNotary) Close() {
t.cmd.Process.Kill()
t.cmd.Process.Wait()
os.RemoveAll(t.dir)
}
func trustedCmd(cmd *icmd.Cmd) func() {
pwd := "12345678"
cmd.Env = append(cmd.Env, trustEnv(notaryURL, pwd, pwd)...)
return nil
}
func trustedCmdWithServer(server string) func(*icmd.Cmd) func() {
return func(cmd *icmd.Cmd) func() {
pwd := "12345678"
cmd.Env = append(cmd.Env, trustEnv(server, pwd, pwd)...)
return nil
}
}
func trustedCmdWithPassphrases(rootPwd, repositoryPwd string) func(*icmd.Cmd) func() {
return func(cmd *icmd.Cmd) func() {
cmd.Env = append(cmd.Env, trustEnv(notaryURL, rootPwd, repositoryPwd)...)
return nil
}
}
func trustEnv(server, rootPwd, repositoryPwd string) []string {
env := append(os.Environ(), []string{
"DOCKER_CONTENT_TRUST=1",
fmt.Sprintf("DOCKER_CONTENT_TRUST_SERVER=%s", server),
fmt.Sprintf("DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE=%s", rootPwd),
fmt.Sprintf("DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE=%s", repositoryPwd),
}...)
return env
}
func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
repoName := fmt.Sprintf("%v/dockercli/%s:latest", privateRegistryURL, name)
// tag the image and upload it to the private registry
cli.DockerCmd(c, "tag", "busybox", repoName)
cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
cli.DockerCmd(c, "rmi", repoName)
return repoName
}
func (s *DockerTrustSuite) setupTrustedplugin(c *check.C, source, name string) string {
repoName := fmt.Sprintf("%v/dockercli/%s:latest", privateRegistryURL, name)
client := testEnv.APIClient()
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
err := plugin.Create(ctx, client, repoName)
cancel()
c.Assert(err, checker.IsNil, check.Commentf("could not create test plugin"))
// tag the image and upload it to the private registry
// TODO: shouldn't need to use the CLI to do trust
cli.Docker(cli.Args("plugin", "push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
ctx, cancel = context.WithTimeout(context.Background(), 60*time.Second)
err = client.PluginRemove(ctx, repoName, types.PluginRemoveOptions{Force: true})
cancel()
c.Assert(err, checker.IsNil, check.Commentf("failed to cleanup test plugin for trust suite"))
return repoName
}
func (s *DockerTrustSuite) notaryCmd(c *check.C, args ...string) string {
pwd := "12345678"
env := []string{
fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", pwd),
fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", pwd),
fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", pwd),
fmt.Sprintf("NOTARY_DELEGATION_PASSPHRASE=%s", pwd),
}
result := icmd.RunCmd(icmd.Cmd{
Command: append([]string{notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json")}, args...),
Env: append(os.Environ(), env...),
})
result.Assert(c, icmd.Success)
return result.Combined()
}
func (s *DockerTrustSuite) notaryInitRepo(c *check.C, repoName string) {
s.notaryCmd(c, "init", repoName)
}
func (s *DockerTrustSuite) notaryCreateDelegation(c *check.C, repoName, role string, pubKey string, paths ...string) {
pathsArg := "--all-paths"
if len(paths) > 0 {
pathsArg = "--paths=" + strings.Join(paths, ",")
}
s.notaryCmd(c, "delegation", "add", repoName, role, pubKey, pathsArg)
}
func (s *DockerTrustSuite) notaryPublish(c *check.C, repoName string) {
s.notaryCmd(c, "publish", repoName)
}
func (s *DockerTrustSuite) notaryImportKey(c *check.C, repoName, role string, privKey string) {
s.notaryCmd(c, "key", "import", privKey, "-g", repoName, "-r", role)
}
func (s *DockerTrustSuite) notaryListTargetsInRole(c *check.C, repoName, role string) map[string]string {
out := s.notaryCmd(c, "list", repoName, "-r", role)
// should look something like:
// NAME DIGEST SIZE (BYTES) ROLE
// ------------------------------------------------------------------------------------------------------
// latest 24a36bbc059b1345b7e8be0df20f1b23caa3602e85d42fff7ecd9d0bd255de56 1377 targets
targets := make(map[string]string)
// no target
lines := strings.Split(strings.TrimSpace(out), "\n")
if len(lines) == 1 && strings.Contains(out, "No targets present in this repository.") {
return targets
}
// otherwise, there is at least one target
c.Assert(len(lines), checker.GreaterOrEqualThan, 3)
for _, line := range lines[2:] {
tokens := strings.Fields(line)
c.Assert(tokens, checker.HasLen, 4)
targets[tokens[0]] = tokens[3]
}
return targets
}
func (s *DockerTrustSuite) assertTargetInRoles(c *check.C, repoName, target string, roles ...string) {
// check all the roles
for _, role := range roles {
targets := s.notaryListTargetsInRole(c, repoName, role)
roleName, ok := targets[target]
c.Assert(ok, checker.True)
c.Assert(roleName, checker.Equals, role)
}
}
func (s *DockerTrustSuite) assertTargetNotInRoles(c *check.C, repoName, target string, roles ...string) {
targets := s.notaryListTargetsInRole(c, repoName, "targets")
roleName, ok := targets[target]
if ok {
for _, role := range roles {
c.Assert(roleName, checker.Not(checker.Equals), role)
}
}
}
@@ -5,6 +5,7 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"strings"
@@ -12,11 +13,13 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/integration-cli/cli/build/fakecontext"
"github.com/docker/docker/integration/internal/request"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/skip"
)
func TestBuildWithRemoveAndForceRemove(t *testing.T) {
@@ -304,6 +307,9 @@ COPY bar /`
// docker/for-linux#135
// #35641
func TestBuildMultiStageLayerLeak(t *testing.T) {
fmt.Println(testEnv.DaemonAPIVersion())
skip.IfCondition(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"),
"Don't run on API lower than 1.38 as it has been fixed starting from that version")
ctx := context.TODO()
defer setupTest(t)()
@@ -59,6 +59,8 @@ func TestNetworkLocalhostTCPNat(t *testing.T) {
func TestNetworkLoopbackNat(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon())
defer setupTest(t)()
msg := "it works"
startServerContainer(t, msg, 8080)
@@ -12,6 +12,7 @@ import (
"github.com/docker/docker/integration-cli/daemon"
"github.com/docker/docker/internal/test/environment"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/gotestyourself/gotestyourself/skip"
)
const (
@@ -21,6 +22,7 @@ const (
// NewSwarm creates a swarm daemon for testing
func NewSwarm(t *testing.T, testEnv *environment.Execution) *daemon.Swarm {
skip.IfCondition(t, testEnv.IsRemoteDaemon())
d := &daemon.Swarm{
Daemon: daemon.New(t, "", dockerdBinary, daemon.Config{
Experimental: testEnv.DaemonInfo.ExperimentalBuild,
@@ -1,16 +1,15 @@
package network // import "github.com/docker/docker/integration/network"
import (
"fmt"
"runtime"
"testing"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
swarmtypes "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/docker/docker/integration-cli/daemon"
"github.com/docker/docker/integration/internal/swarm"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/gotestyourself/gotestyourself/poll"
"golang.org/x/net/context"
@@ -21,7 +20,7 @@ const dockerdBinary = "dockerd"
func TestInspectNetwork(t *testing.T) {
defer setupTest(t)()
d := newSwarm(t)
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
assert.NilError(t, err)
@@ -38,8 +37,9 @@ func TestInspectNetwork(t *testing.T) {
var instances uint64 = 4
serviceName := "TestService"
// FIXME(vdemeester) consolidate with swarm.CreateService
serviceSpec := swarmServiceSpec(serviceName, instances)
serviceSpec.TaskTemplate.Networks = append(serviceSpec.TaskTemplate.Networks, swarm.NetworkAttachmentConfig{Target: overlayName})
serviceSpec.TaskTemplate.Networks = append(serviceSpec.TaskTemplate.Networks, swarmtypes.NetworkAttachmentConfig{Target: overlayName})
serviceResp, err := client.ServiceCreate(context.Background(), serviceSpec, types.ServiceCreateOptions{
QueryRegistry: false,
@@ -107,38 +107,19 @@ func TestInspectNetwork(t *testing.T) {
poll.WaitOn(t, networkIsRemoved(client, overlayID), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
}
func newSwarm(t *testing.T) *daemon.Swarm {
d := &daemon.Swarm{
Daemon: daemon.New(t, "", dockerdBinary, daemon.Config{
Experimental: testEnv.DaemonInfo.ExperimentalBuild,
}),
// TODO: better method of finding an unused port
Port: defaultSwarmPort,
}
// TODO: move to a NewSwarm constructor
d.ListenAddr = fmt.Sprintf("0.0.0.0:%d", d.Port)
// avoid networking conflicts
args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
d.StartWithBusybox(t, args...)
assert.NilError(t, d.Init(swarm.InitRequest{}))
return d
}
func swarmServiceSpec(name string, replicas uint64) swarm.ServiceSpec {
return swarm.ServiceSpec{
Annotations: swarm.Annotations{
func swarmServiceSpec(name string, replicas uint64) swarmtypes.ServiceSpec {
return swarmtypes.ServiceSpec{
Annotations: swarmtypes.Annotations{
Name: name,
},
TaskTemplate: swarm.TaskSpec{
ContainerSpec: &swarm.ContainerSpec{
TaskTemplate: swarmtypes.TaskSpec{
ContainerSpec: &swarmtypes.ContainerSpec{
Image: "busybox:latest",
Command: []string{"/bin/top"},
},
},
Mode: swarm.ServiceMode{
Replicated: &swarm.ReplicatedService{
Mode: swarmtypes.ServiceMode{
Replicated: &swarmtypes.ReplicatedService{
Replicas: &replicas,
},
},
@@ -157,7 +138,7 @@ func serviceRunningTasksCount(client client.ServiceAPIClient, serviceID string,
return poll.Error(err)
case len(tasks) == int(instances):
for _, task := range tasks {
if task.Status.State != swarm.TaskStateRunning {
if task.Status.State != swarmtypes.TaskStateRunning {
return poll.Continue("waiting for tasks to enter run state")
}
}
@@ -7,8 +7,9 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
swarmtypes "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/docker/docker/integration/internal/swarm"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/gotestyourself/gotestyourself/poll"
"golang.org/x/net/context"
@@ -16,7 +17,7 @@ import (
func TestServiceWithPredefinedNetwork(t *testing.T) {
defer setupTest(t)()
d := newSwarm(t)
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
assert.NilError(t, err)
@@ -25,7 +26,7 @@ func TestServiceWithPredefinedNetwork(t *testing.T) {
var instances uint64 = 1
serviceName := "TestService"
serviceSpec := swarmServiceSpec(serviceName, instances)
serviceSpec.TaskTemplate.Networks = append(serviceSpec.TaskTemplate.Networks, swarm.NetworkAttachmentConfig{Target: hostName})
serviceSpec.TaskTemplate.Networks = append(serviceSpec.TaskTemplate.Networks, swarmtypes.NetworkAttachmentConfig{Target: hostName})
serviceResp, err := client.ServiceCreate(context.Background(), serviceSpec, types.ServiceCreateOptions{
QueryRegistry: false,
@@ -60,7 +61,7 @@ const ingressNet = "ingress"
func TestServiceWithIngressNetwork(t *testing.T) {
defer setupTest(t)()
d := newSwarm(t)
d := swarm.NewSwarm(t, testEnv)
defer d.Stop(t)
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
@@ -81,13 +82,13 @@ func TestServiceWithIngressNetwork(t *testing.T) {
var instances uint64 = 1
serviceName := "TestIngressService"
serviceSpec := swarmServiceSpec(serviceName, instances)
serviceSpec.TaskTemplate.Networks = append(serviceSpec.TaskTemplate.Networks, swarm.NetworkAttachmentConfig{Target: ingressNet})
serviceSpec.EndpointSpec = &swarm.EndpointSpec{
Ports: []swarm.PortConfig{
serviceSpec.TaskTemplate.Networks = append(serviceSpec.TaskTemplate.Networks, swarmtypes.NetworkAttachmentConfig{Target: ingressNet})
serviceSpec.EndpointSpec = &swarmtypes.EndpointSpec{
Ports: []swarmtypes.PortConfig{
{
Protocol: swarm.PortConfigProtocolTCP,
Protocol: swarmtypes.PortConfigProtocolTCP,
TargetPort: 80,
PublishMode: swarm.PortConfigPublishModeIngress,
PublishMode: swarmtypes.PortConfigPublishModeIngress,
},
},
}
@@ -16,6 +16,7 @@ import (
"github.com/docker/docker/internal/test/environment"
"github.com/docker/docker/pkg/authorization"
"github.com/docker/docker/pkg/plugins"
"github.com/gotestyourself/gotestyourself/skip"
)
var (
@@ -48,6 +49,7 @@ func TestMain(m *testing.M) {
}
func setupTest(t *testing.T) func() {
skip.IfCondition(t, testEnv.IsRemoteDaemon(), "cannot run daemon when remote daemon")
environment.ProtectAll(t, testEnv)
d = daemon.New(t, "", dockerdBinary, daemon.Config{
@@ -14,8 +14,6 @@ import (
"github.com/pkg/errors"
)
const dockerdBinary = "dockerd"
var pluginBuildLock = locker.New()
func ensurePlugin(t *testing.T, name string) string {
@@ -0,0 +1,31 @@
package logging // import "github.com/docker/docker/integration/plugin/logging"
import (
"fmt"
"os"
"testing"
"github.com/docker/docker/internal/test/environment"
)
var (
testEnv *environment.Execution
)
const dockerdBinary = "dockerd"
func TestMain(m *testing.M) {
var err error
testEnv, err = environment.New()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = environment.EnsureFrozenImagesLinux(testEnv)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
testEnv.Print()
os.Exit(m.Run())
}
@@ -7,12 +7,14 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/integration-cli/daemon"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/gotestyourself/gotestyourself/skip"
)
// Regression test for #35553
// Ensure that a daemon with a log plugin set as the default logger for containers
// does not keep the daemon from starting.
func TestDaemonStartWithLogOpt(t *testing.T) {
skip.IfCondition(t, testEnv.IsRemoteDaemon(), "cannot run daemon when remote daemon")
t.Parallel()
d := daemon.New(t, "", dockerdBinary, daemon.Config{})
@@ -121,6 +121,15 @@ func (e *Execution) IsRemoteDaemon() bool {
return !e.IsLocalDaemon()
}
// DaemonAPIVersion returns the negociated daemon api version
func (e *Execution) DaemonAPIVersion() string {
version, err := e.APIClient().ServerVersion(context.TODO())
if err != nil {
return ""
}
return version.APIVersion
}
// Print the execution details to stdout
// TODO: print everything
func (e *Execution) Print() {
-3
View File
@@ -45,9 +45,6 @@ var (
// IndexName is the name of the index
IndexName = "docker.io"
// NotaryServer is the endpoint serving the Notary trust server
NotaryServer = "https://notary.docker.io"
// DefaultV2Registry is the URI of the default v2 registry
DefaultV2Registry = &url.URL{
Scheme: "https",