Skip to content

Commit ed39fbe

Browse files
committed
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 <[email protected]>
1 parent cd1a1ee commit ed39fbe

4 files changed

Lines changed: 96 additions & 0 deletions

File tree

api/server/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,7 @@ func (s *Server) postContainersCreate(version version.Version, w http.ResponseWr
894894
if err != nil {
895895
return err
896896
}
897+
adjustCpuShares(version, hostConfig)
897898

898899
containerId, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig)
899900
if err != nil {

api/server/server_linux.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,21 @@ import (
88
"net/http"
99
"strconv"
1010

11+
"github.com/Sirupsen/logrus"
1112
"github.com/docker/docker/daemon"
1213
"github.com/docker/docker/pkg/sockets"
1314
"github.com/docker/docker/pkg/systemd"
15+
"github.com/docker/docker/pkg/version"
16+
"github.com/docker/docker/runconfig"
1417
"github.com/docker/libnetwork/portallocator"
1518
)
1619

20+
const (
21+
// See http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269
22+
linuxMinCpuShares = 2
23+
linuxMaxCpuShares = 262144
24+
)
25+
1726
// newServer sets up the required serverClosers and does protocol specific checking.
1827
func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
1928
var (
@@ -96,3 +105,18 @@ func allocateDaemonPort(addr string) error {
96105
}
97106
return nil
98107
}
108+
109+
func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) {
110+
if version.LessThan("1.19") {
111+
if hostConfig.CpuShares > 0 {
112+
// Handle unsupported CpuShares
113+
if hostConfig.CpuShares < linuxMinCpuShares {
114+
logrus.Warnf("Changing requested CpuShares of %d to minimum allowed of %d", hostConfig.CpuShares, linuxMinCpuShares)
115+
hostConfig.CpuShares = linuxMinCpuShares
116+
} else if hostConfig.CpuShares > linuxMaxCpuShares {
117+
logrus.Warnf("Changing requested CpuShares of %d to maximum allowed of %d", hostConfig.CpuShares, linuxMaxCpuShares)
118+
hostConfig.CpuShares = linuxMaxCpuShares
119+
}
120+
}
121+
}
122+
}

api/server/server_linux_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// +build linux
2+
3+
package server
4+
5+
import (
6+
"testing"
7+
8+
"github.com/docker/docker/pkg/version"
9+
"github.com/docker/docker/runconfig"
10+
)
11+
12+
func TestAdjustCpuSharesOldApi(t *testing.T) {
13+
apiVersion := version.Version("1.18")
14+
hostConfig := &runconfig.HostConfig{
15+
CpuShares: linuxMinCpuShares - 1,
16+
}
17+
adjustCpuShares(apiVersion, hostConfig)
18+
if hostConfig.CpuShares != linuxMinCpuShares {
19+
t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares)
20+
}
21+
22+
hostConfig.CpuShares = linuxMaxCpuShares + 1
23+
adjustCpuShares(apiVersion, hostConfig)
24+
if hostConfig.CpuShares != linuxMaxCpuShares {
25+
t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares)
26+
}
27+
28+
hostConfig.CpuShares = 0
29+
adjustCpuShares(apiVersion, hostConfig)
30+
if hostConfig.CpuShares != 0 {
31+
t.Error("Expected CpuShares to be unchanged")
32+
}
33+
34+
hostConfig.CpuShares = 1024
35+
adjustCpuShares(apiVersion, hostConfig)
36+
if hostConfig.CpuShares != 1024 {
37+
t.Error("Expected CpuShares to be unchanged")
38+
}
39+
}
40+
41+
func TestAdjustCpuSharesNoAdjustment(t *testing.T) {
42+
apiVersion := version.Version("1.19")
43+
hostConfig := &runconfig.HostConfig{
44+
CpuShares: linuxMinCpuShares - 1,
45+
}
46+
adjustCpuShares(apiVersion, hostConfig)
47+
if hostConfig.CpuShares != linuxMinCpuShares-1 {
48+
t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares-1)
49+
}
50+
51+
hostConfig.CpuShares = linuxMaxCpuShares + 1
52+
adjustCpuShares(apiVersion, hostConfig)
53+
if hostConfig.CpuShares != linuxMaxCpuShares+1 {
54+
t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares+1)
55+
}
56+
57+
hostConfig.CpuShares = 0
58+
adjustCpuShares(apiVersion, hostConfig)
59+
if hostConfig.CpuShares != 0 {
60+
t.Error("Expected CpuShares to be unchanged")
61+
}
62+
63+
hostConfig.CpuShares = 1024
64+
adjustCpuShares(apiVersion, hostConfig)
65+
if hostConfig.CpuShares != 1024 {
66+
t.Error("Expected CpuShares to be unchanged")
67+
}
68+
}

api/server/server_windows.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,6 @@ func (s *Server) AcceptConnections(d *daemon.Daemon) {
5454
func allocateDaemonPort(addr string) error {
5555
return nil
5656
}
57+
58+
func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) {
59+
}

0 commit comments

Comments
 (0)