From be632872ec37b9266069a96245dbac5bf6df3c3a Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 2 Mar 2018 13:17:56 +0100 Subject: [PATCH 1/5] Fix AppArmor not being applied to Exec processes Exec processes do not automatically inherit AppArmor profiles from the container. This patch sets the AppArmor profile for the exec process. Before this change: apparmor_parser -q -r < profile deny-write flags=(attach_disconnected) { #include file, network, deny /tmp/** w, capability, } EOF docker run -dit --security-opt "apparmor=deny-write" --name aa busybox docker exec aa sh -c 'mkdir /tmp/test' (no error) With this change applied: docker exec aa sh -c 'mkdir /tmp/test' mkdir: can't create directory '/tmp/test': Permission denied Signed-off-by: Sebastiaan van Stijn Upstream-commit: 8f3308ae10ec9ad0dd4edfb46fde53a0e1e19b34 Component: engine --- components/engine/daemon/exec_linux.go | 3 ++ components/engine/daemon/exec_linux_test.go | 53 +++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 components/engine/daemon/exec_linux_test.go diff --git a/components/engine/daemon/exec_linux.go b/components/engine/daemon/exec_linux.go index 1ed26c2fcc..cd52f4886f 100644 --- a/components/engine/daemon/exec_linux.go +++ b/components/engine/daemon/exec_linux.go @@ -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 diff --git a/components/engine/daemon/exec_linux_test.go b/components/engine/daemon/exec_linux_test.go new file mode 100644 index 0000000000..9e5496ae4b --- /dev/null +++ b/components/engine/daemon/exec_linux_test.go @@ -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) +} From 5fc2230d234d105eba1388a483fbe87db8344a7b Mon Sep 17 00:00:00 2001 From: Yanqiang Miao Date: Tue, 13 Mar 2018 10:47:24 +0800 Subject: [PATCH 2/5] add compress option for 'jsonfiles' log driver This PR adds support for compressibility of log file. I added a new option conpression for the jsonfile log driver, this option allows the user to specify compression algorithm to compress the log files. By default, the log files will be not compressed. At present, only support 'gzip'. Signed-off-by: Yanqiang Miao 'docker logs' can read from compressed files Signed-off-by: Yanqiang Miao Add Metadata to the gzip header, optmize 'readlog' Signed-off-by: Yanqiang Miao Upstream-commit: f69f09f44ce9fedbc9d70f11980c1fc8d7f77cec Component: engine --- .../daemon/logger/jsonfilelog/jsonfilelog.go | 18 +- .../logger/jsonfilelog/jsonfilelog_test.go | 64 +++- .../daemon/logger/loggerutils/logfile.go | 289 +++++++++++++++--- 3 files changed, 322 insertions(+), 49 deletions(-) diff --git a/components/engine/daemon/logger/jsonfilelog/jsonfilelog.go b/components/engine/daemon/logger/jsonfilelog/jsonfilelog.go index 5a8045088f..2b1e91d063 100644 --- a/components/engine/daemon/logger/jsonfilelog/jsonfilelog.go +++ b/components/engine/daemon/logger/jsonfilelog/jsonfilelog.go @@ -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": diff --git a/components/engine/daemon/logger/jsonfilelog/jsonfilelog_test.go b/components/engine/daemon/logger/jsonfilelog/jsonfilelog_test.go index 2f74e26091..a5f3d06472 100644 --- a/components/engine/daemon/logger/jsonfilelog/jsonfilelog_test.go +++ b/components/engine/daemon/logger/jsonfilelog/jsonfilelog_test.go @@ -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) { diff --git a/components/engine/daemon/logger/loggerutils/logfile.go b/components/engine/daemon/logger/loggerutils/logfile.go index e646afc23d..b4148ce645 100644 --- a/components/engine/daemon/logger/loggerutils/logfile.go +++ b/components/engine/daemon/logger/loggerutils/logfile.go @@ -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 From aac739f262be67252196efa0bdba64eb7424d445 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Tue, 6 Mar 2018 11:01:26 +0100 Subject: [PATCH 3/5] Migrate DockerTrustSuite to docker/cli e2e tests Signed-off-by: Vincent Demeester Upstream-commit: 5433ceb12ead305d8c85e8e27c4b4d842ef88ae0 Component: engine --- components/engine/Dockerfile | 16 - .../engine/integration-cli/check_test.go | 69 ---- .../integration-cli/docker_cli_build_test.go | 156 -------- .../integration-cli/docker_cli_create_test.go | 71 ---- .../docker_cli_plugins_test.go | 46 --- .../docker_cli_pull_trusted_test.go | 222 ------------ .../integration-cli/docker_cli_push_test.go | 222 ------------ .../integration-cli/docker_cli_run_test.go | 69 ---- .../integration-cli/docker_cli_swarm_test.go | 72 ---- .../integration-cli/docker_utils_test.go | 13 - .../integration-cli/requirements_test.go | 16 - .../integration-cli/trust_server_test.go | 334 ------------------ components/engine/registry/config.go | 3 - 13 files changed, 1309 deletions(-) delete mode 100644 components/engine/integration-cli/docker_cli_pull_trusted_test.go delete mode 100644 components/engine/integration-cli/trust_server_test.go diff --git a/components/engine/Dockerfile b/components/engine/Dockerfile index 63e2dc3f00..c2e279505f 100644 --- a/components/engine/Dockerfile +++ b/components/engine/Dockerfile @@ -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 diff --git a/components/engine/integration-cli/check_test.go b/components/engine/integration-cli/check_test.go index a9f94fb576..18d3d3780a 100644 --- a/components/engine/integration-cli/check_test.go +++ b/components/engine/integration-cli/check_test.go @@ -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{}, diff --git a/components/engine/integration-cli/docker_cli_build_test.go b/components/engine/integration-cli/docker_cli_build_test.go index fc2dafe411..65c63abdb6 100644 --- a/components/engine/integration-cli/docker_cli_build_test.go +++ b/components/engine/integration-cli/docker_cli_build_test.go @@ -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 := ` diff --git a/components/engine/integration-cli/docker_cli_create_test.go b/components/engine/integration-cli/docker_cli_create_test.go index 448af9f199..120b62bc0f 100644 --- a/components/engine/integration-cli/docker_cli_create_test.go +++ b/components/engine/integration-cli/docker_cli_create_test.go @@ -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") diff --git a/components/engine/integration-cli/docker_cli_plugins_test.go b/components/engine/integration-cli/docker_cli_plugins_test.go index 8ca7254440..8a936e3e44 100644 --- a/components/engine/integration-cli/docker_cli_plugins_test.go +++ b/components/engine/integration-cli/docker_cli_plugins_test.go @@ -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() diff --git a/components/engine/integration-cli/docker_cli_pull_trusted_test.go b/components/engine/integration-cli/docker_cli_pull_trusted_test.go deleted file mode 100644 index 60e1c3db1d..0000000000 --- a/components/engine/integration-cli/docker_cli_pull_trusted_test.go +++ /dev/null @@ -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", - }) -} diff --git a/components/engine/integration-cli/docker_cli_push_test.go b/components/engine/integration-cli/docker_cli_push_test.go index 94efa08eab..48d6be2ac1 100644 --- a/components/engine/integration-cli/docker_cli_push_test.go +++ b/components/engine/integration-cli/docker_cli_push_test.go @@ -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) diff --git a/components/engine/integration-cli/docker_cli_run_test.go b/components/engine/integration-cli/docker_cli_run_test.go index 7afbebaccb..a4984862ee 100644 --- a/components/engine/integration-cli/docker_cli_run_test.go +++ b/components/engine/integration-cli/docker_cli_run_test.go @@ -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) diff --git a/components/engine/integration-cli/docker_cli_swarm_test.go b/components/engine/integration-cli/docker_cli_swarm_test.go index 8add18e1ec..4b3358255f 100644 --- a/components/engine/integration-cli/docker_cli_swarm_test.go +++ b/components/engine/integration-cli/docker_cli_swarm_test.go @@ -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) { diff --git a/components/engine/integration-cli/docker_utils_test.go b/components/engine/integration-cli/docker_utils_test.go index ea780cc6e8..1475558239 100644 --- a/components/engine/integration-cli/docker_utils_test.go +++ b/components/engine/integration-cli/docker_utils_test.go @@ -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. diff --git a/components/engine/integration-cli/requirements_test.go b/components/engine/integration-cli/requirements_test.go index 838977e70e..b0a95d42f8 100644 --- a/components/engine/integration-cli/requirements_test.go +++ b/components/engine/integration-cli/requirements_test.go @@ -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") } diff --git a/components/engine/integration-cli/trust_server_test.go b/components/engine/integration-cli/trust_server_test.go deleted file mode 100644 index f312083ee3..0000000000 --- a/components/engine/integration-cli/trust_server_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/components/engine/registry/config.go b/components/engine/registry/config.go index 68bd01c481..de5a526b69 100644 --- a/components/engine/registry/config.go +++ b/components/engine/registry/config.go @@ -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", From d36e75fc44e4bd76a5df3165045e2cfcf1d8c498 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Wed, 14 Mar 2018 11:21:21 +0100 Subject: [PATCH 4/5] integration/*: make e2e run without failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … mainly by skipping if daemon is remote. Signed-off-by: Vincent Demeester Upstream-commit: 6016e79d2552b21643f4bfd093ce76d8ef956d79 Component: engine --- components/engine/hack/test/e2e-run.sh | 6 +-- .../engine/integration/build/build_test.go | 6 +++ .../integration/internal/swarm/service.go | 2 + .../integration/network/inspect_test.go | 45 ++++++------------- .../integration/network/service_test.go | 19 ++++---- .../integration/plugin/authz/main_test.go | 2 + .../plugin/logging/helpers_test.go | 2 - .../integration/plugin/logging/main_test.go | 31 +++++++++++++ .../plugin/logging/validation_test.go | 2 + .../internal/test/environment/environment.go | 9 ++++ 10 files changed, 78 insertions(+), 46 deletions(-) create mode 100644 components/engine/integration/plugin/logging/main_test.go diff --git a/components/engine/hack/test/e2e-run.sh b/components/engine/hack/test/e2e-run.sh index b80f7fc312..b1470d6547 100755 --- a/components/engine/hack/test/e2e-run.sh +++ b/components/engine/hack/test/e2e-run.sh @@ -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 ) diff --git a/components/engine/integration/build/build_test.go b/components/engine/integration/build/build_test.go index 9d396da865..d8cb298cd4 100644 --- a/components/engine/integration/build/build_test.go +++ b/components/engine/integration/build/build_test.go @@ -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)() diff --git a/components/engine/integration/internal/swarm/service.go b/components/engine/integration/internal/swarm/service.go index 0ec4d5175e..79705961a1 100644 --- a/components/engine/integration/internal/swarm/service.go +++ b/components/engine/integration/internal/swarm/service.go @@ -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, diff --git a/components/engine/integration/network/inspect_test.go b/components/engine/integration/network/inspect_test.go index 3afdcf1ac4..ad4a344c49 100644 --- a/components/engine/integration/network/inspect_test.go +++ b/components/engine/integration/network/inspect_test.go @@ -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") } } diff --git a/components/engine/integration/network/service_test.go b/components/engine/integration/network/service_test.go index b8470a1e85..a9fccf9522 100644 --- a/components/engine/integration/network/service_test.go +++ b/components/engine/integration/network/service_test.go @@ -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, }, }, } diff --git a/components/engine/integration/plugin/authz/main_test.go b/components/engine/integration/plugin/authz/main_test.go index ea72a03f16..3d5f406b92 100644 --- a/components/engine/integration/plugin/authz/main_test.go +++ b/components/engine/integration/plugin/authz/main_test.go @@ -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{ diff --git a/components/engine/integration/plugin/logging/helpers_test.go b/components/engine/integration/plugin/logging/helpers_test.go index 61b2f35f43..371d43d831 100644 --- a/components/engine/integration/plugin/logging/helpers_test.go +++ b/components/engine/integration/plugin/logging/helpers_test.go @@ -14,8 +14,6 @@ import ( "github.com/pkg/errors" ) -const dockerdBinary = "dockerd" - var pluginBuildLock = locker.New() func ensurePlugin(t *testing.T, name string) string { diff --git a/components/engine/integration/plugin/logging/main_test.go b/components/engine/integration/plugin/logging/main_test.go new file mode 100644 index 0000000000..b2446ca8c8 --- /dev/null +++ b/components/engine/integration/plugin/logging/main_test.go @@ -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()) +} diff --git a/components/engine/integration/plugin/logging/validation_test.go b/components/engine/integration/plugin/logging/validation_test.go index eb3fe7a029..f0d6e9e8b2 100644 --- a/components/engine/integration/plugin/logging/validation_test.go +++ b/components/engine/integration/plugin/logging/validation_test.go @@ -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{}) diff --git a/components/engine/internal/test/environment/environment.go b/components/engine/internal/test/environment/environment.go index 16f6146334..8e6e2c72fa 100644 --- a/components/engine/internal/test/environment/environment.go +++ b/components/engine/internal/test/environment/environment.go @@ -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() { From ef1461a8723cc882079e5141af3e0c011a67a7f0 Mon Sep 17 00:00:00 2001 From: Arash Deshmeh Date: Mon, 19 Mar 2018 10:55:50 -0400 Subject: [PATCH 5/5] Add the missing call to setupTest to TestNetworkLoopbackNat test function, to avoid leaving behind test containers Signed-off-by: Arash Deshmeh Upstream-commit: a0052b8f190f38bcdd24e4bf794c3ad6d2fd1b41 Component: engine --- components/engine/integration/container/nat_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/engine/integration/container/nat_test.go b/components/engine/integration/container/nat_test.go index 5574db779e..f4a3ea6f3a 100644 --- a/components/engine/integration/container/nat_test.go +++ b/components/engine/integration/container/nat_test.go @@ -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)