diff --git a/components/engine/cmd/dockerd/config.go b/components/engine/cmd/dockerd/config.go index c4ae197335..c7da6ee4f0 100644 --- a/components/engine/cmd/dockerd/config.go +++ b/components/engine/cmd/dockerd/config.go @@ -92,6 +92,8 @@ func installRegistryServiceFlags(options *registry.ServiceOptions, flags *pflag. flags.Var(insecureRegistries, "insecure-registry", "Enable insecure registry communication") if runtime.GOOS != "windows" { + // TODO: Remove this flag after 3 release cycles (18.03) flags.BoolVar(&options.V2Only, "disable-legacy-registry", true, "Disable contacting legacy registries") + flags.MarkHidden("disable-legacy-registry") } } diff --git a/components/engine/cmd/dockerd/daemon.go b/components/engine/cmd/dockerd/daemon.go index 02a03141df..d73b63a0f0 100644 --- a/components/engine/cmd/dockerd/daemon.go +++ b/components/engine/cmd/dockerd/daemon.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "strings" "time" @@ -472,8 +473,15 @@ func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) { return nil, err } - if !conf.V2Only { - logrus.Warnf(`The "disable-legacy-registry" option is deprecated and wil be removed in Docker v17.12. Interacting with legacy (v1) registries will no longer be supported in Docker v17.12"`) + if runtime.GOOS != "windows" { + if flags.Changed("disable-legacy-registry") { + // TODO: Remove this error after 3 release cycles (18.03) + return nil, errors.New("ERROR: The '--disable-legacy-registry' flag has been removed. Interacting with legacy (v1) registries is no longer supported") + } + if !conf.V2Only { + // TODO: Remove this error after 3 release cycles (18.03) + return nil, errors.New("ERROR: The 'disable-legacy-registry' configuration option has been removed. Interacting with legacy (v1) registries is no longer supported") + } } if flags.Changed("graph") { diff --git a/components/engine/cmd/dockerd/daemon_unix_test.go b/components/engine/cmd/dockerd/daemon_unix_test.go index 475ff9efa7..41c392e1b1 100644 --- a/components/engine/cmd/dockerd/daemon_unix_test.go +++ b/components/engine/cmd/dockerd/daemon_unix_test.go @@ -97,15 +97,3 @@ func TestLoadDaemonConfigWithTrueDefaultValuesLeaveDefaults(t *testing.T) { assert.True(t, loadedConfig.EnableUserlandProxy) } - -func TestLoadDaemonConfigWithLegacyRegistryOptions(t *testing.T) { - content := `{"disable-legacy-registry": false}` - tempFile := fs.NewFile(t, "config", fs.WithContent(content)) - defer tempFile.Remove() - - opts := defaultOptions(tempFile.Path()) - loadedConfig, err := loadDaemonCliConfig(opts) - require.NoError(t, err) - require.NotNil(t, loadedConfig) - assert.False(t, loadedConfig.V2Only) -} diff --git a/components/engine/daemon/graphdriver/devmapper/deviceset.go b/components/engine/daemon/graphdriver/devmapper/deviceset.go index db41f05097..6659878bc6 100644 --- a/components/engine/daemon/graphdriver/devmapper/deviceset.go +++ b/components/engine/daemon/graphdriver/devmapper/deviceset.go @@ -1201,7 +1201,7 @@ func (devices *DeviceSet) growFS(info *devInfo) error { options = joinMountOptions(options, devices.mountOptions) if err := mount.Mount(info.DevName(), fsMountPoint, devices.BaseDeviceFilesystem, options); err != nil { - return fmt.Errorf("Error mounting '%s' on '%s': %s\n%v", info.DevName(), fsMountPoint, err, string(dmesg.Dmesg(256))) + return fmt.Errorf("Error mounting '%s' on '%s' (fstype='%s' options='%s'): %s\n%v", info.DevName(), fsMountPoint, devices.BaseDeviceFilesystem, options, err, string(dmesg.Dmesg(256))) } defer unix.Unmount(fsMountPoint, unix.MNT_DETACH) @@ -2392,7 +2392,7 @@ func (devices *DeviceSet) MountDevice(hash, path, mountLabel string) error { options = joinMountOptions(options, label.FormatMountLabel("", mountLabel)) if err := mount.Mount(info.DevName(), path, fstype, options); err != nil { - return fmt.Errorf("devmapper: Error mounting '%s' on '%s': %s\n%v", info.DevName(), path, err, string(dmesg.Dmesg(256))) + return fmt.Errorf("devmapper: Error mounting '%s' on '%s' (fstype='%s' options='%s'): %s\n%v", info.DevName(), path, fstype, options, err, string(dmesg.Dmesg(256))) } if fstype == "xfs" && devices.xfsNospaceRetries != "" { diff --git a/components/engine/integration-cli/docker_api_logs_test.go b/components/engine/integration-cli/docker_api_logs_test.go index 41164df314..ef1e77d88b 100644 --- a/components/engine/integration-cli/docker_api_logs_test.go +++ b/components/engine/integration-cli/docker_api_logs_test.go @@ -151,7 +151,7 @@ func (s *DockerSuite) TestLogsAPIUntilFutureFollow(c *check.C) { func (s *DockerSuite) TestLogsAPIUntil(c *check.C) { name := "logsuntil" - dockerCmd(c, "run", "--name", name, "busybox", "/bin/sh", "-c", "for i in $(seq 1 3); do echo log$i; done") + dockerCmd(c, "run", "--name", name, "busybox", "/bin/sh", "-c", "for i in $(seq 1 3); do echo log$i; sleep 1; done") client, err := request.NewClient() if err != nil { diff --git a/components/engine/integration-cli/docker_cli_logout_test.go b/components/engine/integration-cli/docker_cli_logout_test.go index 5076ceba09..e0752f489c 100644 --- a/components/engine/integration-cli/docker_cli_logout_test.go +++ b/components/engine/integration-cli/docker_cli_logout_test.go @@ -13,9 +13,7 @@ import ( ) func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithExternalAuth(c *check.C) { - - // @TODO TestLogoutWithExternalAuth expects docker to fall back to a v1 registry, so has to be updated for v17.12, when v1 registries are no longer supported - s.d.StartWithBusybox(c, "--disable-legacy-registry=false") + s.d.StartWithBusybox(c) osPath := os.Getenv("PATH") defer os.Setenv("PATH", osPath) @@ -62,7 +60,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithExternalAuth(c *check.C) // check I cannot pull anymore out, err := s.d.Cmd("--config", tmp, "pull", repoName) c.Assert(err, check.NotNil, check.Commentf(out)) - c.Assert(out, checker.Contains, "Error: image dockercli/busybox:authtest not found") + c.Assert(out, checker.Contains, "no basic auth credentials") } // #23100 diff --git a/components/engine/integration-cli/docker_cli_pull_test.go b/components/engine/integration-cli/docker_cli_pull_test.go index 613cdb311f..0e88b1e56f 100644 --- a/components/engine/integration-cli/docker_cli_pull_test.go +++ b/components/engine/integration-cli/docker_cli_pull_test.go @@ -259,18 +259,6 @@ func (s *DockerHubPullSuite) TestPullClientDisconnect(c *check.C) { c.Assert(err, checker.NotNil, check.Commentf("image was pulled after client disconnected")) } -func (s *DockerRegistryAuthHtpasswdSuite) TestPullNoCredentialsNotFound(c *check.C) { - // @TODO TestPullNoCredentialsNotFound expects docker to fall back to a v1 registry, so has to be updated for v17.12, when v1 registries are no longer supported - s.d.StartWithBusybox(c, "--disable-legacy-registry=false") - - // we don't care about the actual image, we just want to see image not found - // because that means v2 call returned 401 and we fell back to v1 which usually - // gives a 404 (in this case the test registry doesn't handle v1 at all) - out, err := s.d.Cmd("pull", privateRegistryURL+"/busybox") - c.Assert(err, check.NotNil, check.Commentf(out)) - c.Assert(out, checker.Contains, "Error: image busybox:latest not found") -} - // Regression test for https://github.com/docker/docker/issues/26429 func (s *DockerSuite) TestPullLinuxImageFailsOnWindows(c *check.C) { testRequires(c, DaemonIsWindows, Network) diff --git a/components/engine/integration-cli/docker_cli_v2_only_test.go b/components/engine/integration-cli/docker_cli_v2_only_test.go index b82cdbde1f..3757341025 100644 --- a/components/engine/integration-cli/docker_cli_v2_only_test.go +++ b/components/engine/integration-cli/docker_cli_v2_only_test.go @@ -22,7 +22,7 @@ func makefile(path string, contents string) (string, error) { return f.Name(), nil } -// TestV2Only ensures that a daemon by default does not +// TestV2Only ensures that a daemon does not // attempt to contact any v1 registry endpoints. func (s *DockerRegistrySuite) TestV2Only(c *check.C) { reg, err := registry.NewMock(c) @@ -56,65 +56,3 @@ func (s *DockerRegistrySuite) TestV2Only(c *check.C) { s.d.Cmd("push", repoName) s.d.Cmd("pull", repoName) } - -// TestV1 starts a daemon with legacy registries enabled -// and ensure v1 endpoints are hit for the following operations: -// login, push, pull, build & run -func (s *DockerRegistrySuite) TestV1(c *check.C) { - reg, err := registry.NewMock(c) - defer reg.Close() - c.Assert(err, check.IsNil) - - v2Pings := 0 - reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { - v2Pings++ - // V2 ping 404 causes fallback to v1 - w.WriteHeader(404) - }) - - v1Pings := 0 - reg.RegisterHandler("/v1/_ping", func(w http.ResponseWriter, r *http.Request) { - v1Pings++ - }) - - v1Logins := 0 - reg.RegisterHandler("/v1/users/", func(w http.ResponseWriter, r *http.Request) { - v1Logins++ - }) - - v1Repo := 0 - reg.RegisterHandler("/v1/repositories/busybox/", func(w http.ResponseWriter, r *http.Request) { - v1Repo++ - }) - - reg.RegisterHandler("/v1/repositories/busybox/images", func(w http.ResponseWriter, r *http.Request) { - v1Repo++ - }) - - s.d.Start(c, "--insecure-registry", reg.URL(), "--disable-legacy-registry=false") - - tmp, err := ioutil.TempDir("", "integration-cli-") - c.Assert(err, check.IsNil) - defer os.RemoveAll(tmp) - - dockerfileName, err := makefile(tmp, fmt.Sprintf("FROM %s/busybox", reg.URL())) - c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile")) - - s.d.Cmd("build", "--file", dockerfileName, tmp) - c.Assert(v1Repo, check.Equals, 1, check.Commentf("Expected v1 repository access after build")) - - repoName := fmt.Sprintf("%s/busybox", reg.URL()) - s.d.Cmd("run", repoName) - c.Assert(v1Repo, check.Equals, 2, check.Commentf("Expected v1 repository access after run")) - - s.d.Cmd("login", "-u", "richard", "-p", "testtest", reg.URL()) - c.Assert(v1Logins, check.Equals, 1, check.Commentf("Expected v1 login attempt")) - - s.d.Cmd("tag", "busybox", repoName) - s.d.Cmd("push", repoName) - - c.Assert(v1Repo, check.Equals, 2) - - s.d.Cmd("pull", repoName) - c.Assert(v1Repo, check.Equals, 3, check.Commentf("Expected v1 repository access after pull")) -} diff --git a/components/engine/libcontainerd/remote_daemon.go b/components/engine/libcontainerd/remote_daemon.go index e6fd05f08a..609bcfba7a 100644 --- a/components/engine/libcontainerd/remote_daemon.go +++ b/components/engine/libcontainerd/remote_daemon.go @@ -278,7 +278,7 @@ func (r *remote) monitorConnection(client *containerd.Client) { select { case <-r.shutdownContext.Done(): - r.logger.Info("stopping healtcheck following graceful shutdown") + r.logger.Info("stopping healthcheck following graceful shutdown") client.Close() return default: diff --git a/components/engine/vendor.conf b/components/engine/vendor.conf index 9ff52908b5..87f7930262 100644 --- a/components/engine/vendor.conf +++ b/components/engine/vendor.conf @@ -77,7 +77,7 @@ github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852 github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4 # gelf logging driver deps -github.com/Graylog2/go-gelf v2 +github.com/Graylog2/go-gelf 4143646226541087117ff2f83334ea48b3201841 github.com/fluent/fluent-logger-golang v1.3.0 # fluent-logger-golang deps diff --git a/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/tcpreader.go b/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/tcpreader.go index 8f22c9aea4..74255ec3be 100644 --- a/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/tcpreader.go +++ b/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/tcpreader.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "net" + "time" ) type TCPReader struct { @@ -13,16 +14,21 @@ type TCPReader struct { messages chan []byte } -func newTCPReader(addr string) (*TCPReader, chan string, error) { +type connChannels struct { + drop chan string + confirm chan string +} + +func newTCPReader(addr string) (*TCPReader, chan string, chan string, error) { var err error tcpAddr, err := net.ResolveTCPAddr("tcp", addr) if err != nil { - return nil, nil, fmt.Errorf("ResolveTCPAddr('%s'): %s", addr, err) + return nil, nil, nil, fmt.Errorf("ResolveTCPAddr('%s'): %s", addr, err) } listener, err := net.ListenTCP("tcp", tcpAddr) if err != nil { - return nil, nil, fmt.Errorf("ListenTCP: %s", err) + return nil, nil, nil, fmt.Errorf("ListenTCP: %s", err) } r := &TCPReader{ @@ -30,26 +36,61 @@ func newTCPReader(addr string) (*TCPReader, chan string, error) { messages: make(chan []byte, 100), // Make a buffered channel with at most 100 messages } - signal := make(chan string, 1) + closeSignal := make(chan string, 1) + doneSignal := make(chan string, 1) - go r.listenUntilCloseSignal(signal) + go r.listenUntilCloseSignal(closeSignal, doneSignal) - return r, signal, nil + return r, closeSignal, doneSignal, nil } -func (r *TCPReader) listenUntilCloseSignal(signal chan string) { - defer func() { signal <- "done" }() - defer r.listener.Close() +func (r *TCPReader) accepter(connections chan net.Conn) { for { conn, err := r.listener.Accept() if err != nil { break } - go handleConnection(conn, r.messages) + connections <- conn + } +} + +func (r *TCPReader) listenUntilCloseSignal(closeSignal chan string, doneSignal chan string) { + defer func() { doneSignal <- "done" }() + defer r.listener.Close() + var conns []connChannels + connectionsChannel := make(chan net.Conn, 1) + go r.accepter(connectionsChannel) + for { select { - case sig := <-signal: - if sig == "stop" { - break + case conn := <-connectionsChannel: + dropSignal := make(chan string, 1) + dropConfirm := make(chan string, 1) + channels := connChannels{drop: dropSignal, confirm: dropConfirm} + go handleConnection(conn, r.messages, dropSignal, dropConfirm) + conns = append(conns, channels) + default: + } + + select { + case sig := <-closeSignal: + if sig == "stop" || sig == "drop" { + if len(conns) >= 1 { + for _, s := range conns { + if s.drop != nil { + s.drop <- "drop" + <-s.confirm + conns = append(conns[:0], conns[1:]...) + } + } + if sig == "stop" { + return + } + } else if sig == "stop" { + closeSignal <- "stop" + } + if sig == "drop" { + doneSignal <- "done" + } } default: } @@ -60,19 +101,41 @@ func (r *TCPReader) addr() string { return r.listener.Addr().String() } -func handleConnection(conn net.Conn, messages chan<- []byte) { +func handleConnection(conn net.Conn, messages chan<- []byte, dropSignal chan string, dropConfirm chan string) { + defer func() { dropConfirm <- "done" }() defer conn.Close() reader := bufio.NewReader(conn) var b []byte var err error + drop := false + canDrop := false for { + conn.SetDeadline(time.Now().Add(2 * time.Second)) if b, err = reader.ReadBytes(0); err != nil { - continue - } - if len(b) > 0 { + if drop { + return + } + } else if len(b) > 0 { messages <- b + canDrop = true + if drop { + return + } + } else if drop { + return + } + select { + case sig := <-dropSignal: + if sig == "drop" { + drop = true + time.Sleep(1 * time.Second) + if canDrop { + return + } + } + default: } } } diff --git a/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/tcpwriter.go b/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/tcpwriter.go index ab95cbcd02..da1390d1d6 100644 --- a/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/tcpwriter.go +++ b/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/tcpwriter.go @@ -75,12 +75,17 @@ func (w *TCPWriter) Write(p []byte) (n int, err error) { func (w *TCPWriter) writeToSocketWithReconnectAttempts(zBytes []byte) (n int, err error) { var errConn error + var i int w.mu.Lock() - for i := 0; n <= w.MaxReconnect; i++ { + for i = 0; i <= w.MaxReconnect; i++ { errConn = nil - n, err = w.conn.Write(zBytes) + if w.conn != nil { + n, err = w.conn.Write(zBytes) + } else { + err = fmt.Errorf("Connection was nil, will attempt reconnect") + } if err != nil { time.Sleep(w.ReconnectDelay * time.Second) w.conn, errConn = net.Dial("tcp", w.addr) @@ -90,6 +95,9 @@ func (w *TCPWriter) writeToSocketWithReconnectAttempts(zBytes []byte) (n int, er } w.mu.Unlock() + if i > w.MaxReconnect { + return 0, fmt.Errorf("Maximum reconnection attempts was reached; giving up") + } if errConn != nil { return 0, fmt.Errorf("Write Failed: %s\nReconnection failed: %s", err, errConn) } diff --git a/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/writer.go b/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/writer.go index 93c36929b4..153be2c340 100644 --- a/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/writer.go +++ b/components/engine/vendor/github.com/Graylog2/go-gelf/gelf/writer.go @@ -27,5 +27,8 @@ type GelfWriter struct { // Close connection and interrupt blocked Read or Write operations func (w *GelfWriter) Close() error { + if w.conn == nil { + return nil + } return w.conn.Close() }