From 984be835dbdcc5e4da58c5bc3a7ad2ed0f487799 Mon Sep 17 00:00:00 2001 From: Samuel Karp Date: Wed, 3 Jun 2015 12:01:53 -0700 Subject: [PATCH] Adjust disallowed CpuShares in /containers/create Previous versions of libcontainer allowed CpuShares that were greater than the maximum or less than the minimum supported by the kernel, and relied on the kernel to do the right thing. Newer libcontainer fails after creating the container if the requested CpuShares is different from what was actually created by the kernel, which breaks compatibility with earlier Docker Remote API versions. This change explicitly adjusts the requested CpuShares in API versions < 1.20. Signed-off-by: Samuel Karp (cherry picked from commit ed39fbeb2ad3959f37cf6c16aaf30aacb3292817) --- api/server/server.go | 1 + api/server/server_linux.go | 24 ++++++++++++ api/server/server_linux_test.go | 68 +++++++++++++++++++++++++++++++++ api/server/server_windows.go | 3 ++ 4 files changed, 96 insertions(+) create mode 100644 api/server/server_linux_test.go diff --git a/api/server/server.go b/api/server/server.go index 7a0ff4f0b..c30cd1407 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -903,6 +903,7 @@ func (s *Server) postContainersCreate(version version.Version, w http.ResponseWr if err != nil { return err } + adjustCpuShares(version, hostConfig) containerId, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig) if err != nil { diff --git a/api/server/server_linux.go b/api/server/server_linux.go index f1a3c8825..93dd42990 100644 --- a/api/server/server_linux.go +++ b/api/server/server_linux.go @@ -8,12 +8,21 @@ import ( "net/http" "strconv" + "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon" "github.com/docker/docker/pkg/sockets" "github.com/docker/docker/pkg/systemd" + "github.com/docker/docker/pkg/version" + "github.com/docker/docker/runconfig" "github.com/docker/libnetwork/portallocator" ) +const ( + // See http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269 + linuxMinCpuShares = 2 + linuxMaxCpuShares = 262144 +) + // newServer sets up the required serverClosers and does protocol specific checking. func (s *Server) newServer(proto, addr string) ([]serverCloser, error) { var ( @@ -96,3 +105,18 @@ func allocateDaemonPort(addr string) error { } return nil } + +func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) { + if version.LessThan("1.19") { + if hostConfig.CpuShares > 0 { + // Handle unsupported CpuShares + if hostConfig.CpuShares < linuxMinCpuShares { + logrus.Warnf("Changing requested CpuShares of %d to minimum allowed of %d", hostConfig.CpuShares, linuxMinCpuShares) + hostConfig.CpuShares = linuxMinCpuShares + } else if hostConfig.CpuShares > linuxMaxCpuShares { + logrus.Warnf("Changing requested CpuShares of %d to maximum allowed of %d", hostConfig.CpuShares, linuxMaxCpuShares) + hostConfig.CpuShares = linuxMaxCpuShares + } + } + } +} diff --git a/api/server/server_linux_test.go b/api/server/server_linux_test.go new file mode 100644 index 000000000..47289653e --- /dev/null +++ b/api/server/server_linux_test.go @@ -0,0 +1,68 @@ +// +build linux + +package server + +import ( + "testing" + + "github.com/docker/docker/pkg/version" + "github.com/docker/docker/runconfig" +) + +func TestAdjustCpuSharesOldApi(t *testing.T) { + apiVersion := version.Version("1.18") + hostConfig := &runconfig.HostConfig{ + CpuShares: linuxMinCpuShares - 1, + } + adjustCpuShares(apiVersion, hostConfig) + if hostConfig.CpuShares != linuxMinCpuShares { + t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares) + } + + hostConfig.CpuShares = linuxMaxCpuShares + 1 + adjustCpuShares(apiVersion, hostConfig) + if hostConfig.CpuShares != linuxMaxCpuShares { + t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares) + } + + hostConfig.CpuShares = 0 + adjustCpuShares(apiVersion, hostConfig) + if hostConfig.CpuShares != 0 { + t.Error("Expected CpuShares to be unchanged") + } + + hostConfig.CpuShares = 1024 + adjustCpuShares(apiVersion, hostConfig) + if hostConfig.CpuShares != 1024 { + t.Error("Expected CpuShares to be unchanged") + } +} + +func TestAdjustCpuSharesNoAdjustment(t *testing.T) { + apiVersion := version.Version("1.19") + hostConfig := &runconfig.HostConfig{ + CpuShares: linuxMinCpuShares - 1, + } + adjustCpuShares(apiVersion, hostConfig) + if hostConfig.CpuShares != linuxMinCpuShares-1 { + t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares-1) + } + + hostConfig.CpuShares = linuxMaxCpuShares + 1 + adjustCpuShares(apiVersion, hostConfig) + if hostConfig.CpuShares != linuxMaxCpuShares+1 { + t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares+1) + } + + hostConfig.CpuShares = 0 + adjustCpuShares(apiVersion, hostConfig) + if hostConfig.CpuShares != 0 { + t.Error("Expected CpuShares to be unchanged") + } + + hostConfig.CpuShares = 1024 + adjustCpuShares(apiVersion, hostConfig) + if hostConfig.CpuShares != 1024 { + t.Error("Expected CpuShares to be unchanged") + } +} diff --git a/api/server/server_windows.go b/api/server/server_windows.go index f03025e17..cc5c323be 100644 --- a/api/server/server_windows.go +++ b/api/server/server_windows.go @@ -48,3 +48,6 @@ func (s *Server) AcceptConnections(d *daemon.Daemon) { func allocateDaemonPort(addr string) error { return nil } + +func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) { +}