github.com/sams1990/dockerrepo@v17.12.1-ce-rc2+incompatible/integration-cli/docker_cli_update_unix_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "context" 7 "encoding/json" 8 "fmt" 9 "os/exec" 10 "strings" 11 "time" 12 13 "github.com/docker/docker/api/types" 14 "github.com/docker/docker/client" 15 "github.com/docker/docker/integration-cli/checker" 16 "github.com/docker/docker/integration-cli/request" 17 "github.com/docker/docker/pkg/parsers/kernel" 18 "github.com/go-check/check" 19 "github.com/kr/pty" 20 ) 21 22 func (s *DockerSuite) TestUpdateRunningContainer(c *check.C) { 23 testRequires(c, DaemonIsLinux) 24 testRequires(c, memoryLimitSupport) 25 26 name := "test-update-container" 27 dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "top") 28 dockerCmd(c, "update", "-m", "500M", name) 29 30 c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "524288000") 31 32 file := "/sys/fs/cgroup/memory/memory.limit_in_bytes" 33 out, _ := dockerCmd(c, "exec", name, "cat", file) 34 c.Assert(strings.TrimSpace(out), checker.Equals, "524288000") 35 } 36 37 func (s *DockerSuite) TestUpdateRunningContainerWithRestart(c *check.C) { 38 testRequires(c, DaemonIsLinux) 39 testRequires(c, memoryLimitSupport) 40 41 name := "test-update-container" 42 dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "top") 43 dockerCmd(c, "update", "-m", "500M", name) 44 dockerCmd(c, "restart", name) 45 46 c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "524288000") 47 48 file := "/sys/fs/cgroup/memory/memory.limit_in_bytes" 49 out, _ := dockerCmd(c, "exec", name, "cat", file) 50 c.Assert(strings.TrimSpace(out), checker.Equals, "524288000") 51 } 52 53 func (s *DockerSuite) TestUpdateStoppedContainer(c *check.C) { 54 testRequires(c, DaemonIsLinux) 55 testRequires(c, memoryLimitSupport) 56 57 name := "test-update-container" 58 file := "/sys/fs/cgroup/memory/memory.limit_in_bytes" 59 dockerCmd(c, "run", "--name", name, "-m", "300M", "busybox", "cat", file) 60 dockerCmd(c, "update", "-m", "500M", name) 61 62 c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "524288000") 63 64 out, _ := dockerCmd(c, "start", "-a", name) 65 c.Assert(strings.TrimSpace(out), checker.Equals, "524288000") 66 } 67 68 func (s *DockerSuite) TestUpdatePausedContainer(c *check.C) { 69 testRequires(c, DaemonIsLinux) 70 testRequires(c, cpuShare) 71 72 name := "test-update-container" 73 dockerCmd(c, "run", "-d", "--name", name, "--cpu-shares", "1000", "busybox", "top") 74 dockerCmd(c, "pause", name) 75 dockerCmd(c, "update", "--cpu-shares", "500", name) 76 77 c.Assert(inspectField(c, name, "HostConfig.CPUShares"), checker.Equals, "500") 78 79 dockerCmd(c, "unpause", name) 80 file := "/sys/fs/cgroup/cpu/cpu.shares" 81 out, _ := dockerCmd(c, "exec", name, "cat", file) 82 c.Assert(strings.TrimSpace(out), checker.Equals, "500") 83 } 84 85 func (s *DockerSuite) TestUpdateWithUntouchedFields(c *check.C) { 86 testRequires(c, DaemonIsLinux) 87 testRequires(c, memoryLimitSupport) 88 testRequires(c, cpuShare) 89 90 name := "test-update-container" 91 dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "--cpu-shares", "800", "busybox", "top") 92 dockerCmd(c, "update", "-m", "500M", name) 93 94 // Update memory and not touch cpus, `cpuset.cpus` should still have the old value 95 out := inspectField(c, name, "HostConfig.CPUShares") 96 c.Assert(out, check.Equals, "800") 97 98 file := "/sys/fs/cgroup/cpu/cpu.shares" 99 out, _ = dockerCmd(c, "exec", name, "cat", file) 100 c.Assert(strings.TrimSpace(out), checker.Equals, "800") 101 } 102 103 func (s *DockerSuite) TestUpdateContainerInvalidValue(c *check.C) { 104 testRequires(c, DaemonIsLinux) 105 testRequires(c, memoryLimitSupport) 106 107 name := "test-update-container" 108 dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "true") 109 out, _, err := dockerCmdWithError("update", "-m", "2M", name) 110 c.Assert(err, check.NotNil) 111 expected := "Minimum memory limit allowed is 4MB" 112 c.Assert(out, checker.Contains, expected) 113 } 114 115 func (s *DockerSuite) TestUpdateContainerWithoutFlags(c *check.C) { 116 testRequires(c, DaemonIsLinux) 117 testRequires(c, memoryLimitSupport) 118 119 name := "test-update-container" 120 dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "true") 121 _, _, err := dockerCmdWithError("update", name) 122 c.Assert(err, check.NotNil) 123 } 124 125 func (s *DockerSuite) TestUpdateKernelMemory(c *check.C) { 126 testRequires(c, DaemonIsLinux, kernelMemorySupport) 127 128 name := "test-update-container" 129 dockerCmd(c, "run", "-d", "--name", name, "--kernel-memory", "50M", "busybox", "top") 130 dockerCmd(c, "update", "--kernel-memory", "100M", name) 131 132 c.Assert(inspectField(c, name, "HostConfig.KernelMemory"), checker.Equals, "104857600") 133 134 file := "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes" 135 out, _ := dockerCmd(c, "exec", name, "cat", file) 136 c.Assert(strings.TrimSpace(out), checker.Equals, "104857600") 137 } 138 139 func (s *DockerSuite) TestUpdateKernelMemoryUninitialized(c *check.C) { 140 testRequires(c, DaemonIsLinux, kernelMemorySupport) 141 142 isNewKernel := CheckKernelVersion(4, 6, 0) 143 name := "test-update-container" 144 dockerCmd(c, "run", "-d", "--name", name, "busybox", "top") 145 _, _, err := dockerCmdWithError("update", "--kernel-memory", "100M", name) 146 // Update kernel memory to a running container without kernel memory initialized 147 // is not allowed before kernel version 4.6. 148 if !isNewKernel { 149 c.Assert(err, check.NotNil) 150 } else { 151 c.Assert(err, check.IsNil) 152 } 153 154 dockerCmd(c, "pause", name) 155 _, _, err = dockerCmdWithError("update", "--kernel-memory", "200M", name) 156 if !isNewKernel { 157 c.Assert(err, check.NotNil) 158 } else { 159 c.Assert(err, check.IsNil) 160 } 161 dockerCmd(c, "unpause", name) 162 163 dockerCmd(c, "stop", name) 164 dockerCmd(c, "update", "--kernel-memory", "300M", name) 165 dockerCmd(c, "start", name) 166 167 c.Assert(inspectField(c, name, "HostConfig.KernelMemory"), checker.Equals, "314572800") 168 169 file := "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes" 170 out, _ := dockerCmd(c, "exec", name, "cat", file) 171 c.Assert(strings.TrimSpace(out), checker.Equals, "314572800") 172 } 173 174 // GetKernelVersion gets the current kernel version. 175 func GetKernelVersion() *kernel.VersionInfo { 176 v, _ := kernel.ParseRelease(testEnv.DaemonInfo.KernelVersion) 177 return v 178 } 179 180 // CheckKernelVersion checks if current kernel is newer than (or equal to) 181 // the given version. 182 func CheckKernelVersion(k, major, minor int) bool { 183 return kernel.CompareKernelVersion(*GetKernelVersion(), kernel.VersionInfo{Kernel: k, Major: major, Minor: minor}) >= 0 184 } 185 186 func (s *DockerSuite) TestUpdateSwapMemoryOnly(c *check.C) { 187 testRequires(c, DaemonIsLinux) 188 testRequires(c, memoryLimitSupport) 189 testRequires(c, swapMemorySupport) 190 191 name := "test-update-container" 192 dockerCmd(c, "run", "-d", "--name", name, "--memory", "300M", "--memory-swap", "500M", "busybox", "top") 193 dockerCmd(c, "update", "--memory-swap", "600M", name) 194 195 c.Assert(inspectField(c, name, "HostConfig.MemorySwap"), checker.Equals, "629145600") 196 197 file := "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes" 198 out, _ := dockerCmd(c, "exec", name, "cat", file) 199 c.Assert(strings.TrimSpace(out), checker.Equals, "629145600") 200 } 201 202 func (s *DockerSuite) TestUpdateInvalidSwapMemory(c *check.C) { 203 testRequires(c, DaemonIsLinux) 204 testRequires(c, memoryLimitSupport) 205 testRequires(c, swapMemorySupport) 206 207 name := "test-update-container" 208 dockerCmd(c, "run", "-d", "--name", name, "--memory", "300M", "--memory-swap", "500M", "busybox", "top") 209 _, _, err := dockerCmdWithError("update", "--memory-swap", "200M", name) 210 // Update invalid swap memory should fail. 211 // This will pass docker config validation, but failed at kernel validation 212 c.Assert(err, check.NotNil) 213 214 // Update invalid swap memory with failure should not change HostConfig 215 c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "314572800") 216 c.Assert(inspectField(c, name, "HostConfig.MemorySwap"), checker.Equals, "524288000") 217 218 dockerCmd(c, "update", "--memory-swap", "600M", name) 219 220 c.Assert(inspectField(c, name, "HostConfig.MemorySwap"), checker.Equals, "629145600") 221 222 file := "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes" 223 out, _ := dockerCmd(c, "exec", name, "cat", file) 224 c.Assert(strings.TrimSpace(out), checker.Equals, "629145600") 225 } 226 227 func (s *DockerSuite) TestUpdateStats(c *check.C) { 228 testRequires(c, DaemonIsLinux) 229 testRequires(c, memoryLimitSupport) 230 testRequires(c, cpuCfsQuota) 231 name := "foo" 232 dockerCmd(c, "run", "-d", "-ti", "--name", name, "-m", "500m", "busybox") 233 234 c.Assert(waitRun(name), checker.IsNil) 235 236 getMemLimit := func(id string) uint64 { 237 resp, body, err := request.Get(fmt.Sprintf("/containers/%s/stats?stream=false", id)) 238 c.Assert(err, checker.IsNil) 239 c.Assert(resp.Header.Get("Content-Type"), checker.Equals, "application/json") 240 241 var v *types.Stats 242 err = json.NewDecoder(body).Decode(&v) 243 c.Assert(err, checker.IsNil) 244 body.Close() 245 246 return v.MemoryStats.Limit 247 } 248 preMemLimit := getMemLimit(name) 249 250 dockerCmd(c, "update", "--cpu-quota", "2000", name) 251 252 curMemLimit := getMemLimit(name) 253 254 c.Assert(preMemLimit, checker.Equals, curMemLimit) 255 256 } 257 258 func (s *DockerSuite) TestUpdateMemoryWithSwapMemory(c *check.C) { 259 testRequires(c, DaemonIsLinux) 260 testRequires(c, memoryLimitSupport) 261 testRequires(c, swapMemorySupport) 262 263 name := "test-update-container" 264 dockerCmd(c, "run", "-d", "--name", name, "--memory", "300M", "busybox", "top") 265 out, _, err := dockerCmdWithError("update", "--memory", "800M", name) 266 c.Assert(err, checker.NotNil) 267 c.Assert(out, checker.Contains, "Memory limit should be smaller than already set memoryswap limit") 268 269 dockerCmd(c, "update", "--memory", "800M", "--memory-swap", "1000M", name) 270 } 271 272 func (s *DockerSuite) TestUpdateNotAffectMonitorRestartPolicy(c *check.C) { 273 testRequires(c, DaemonIsLinux, cpuShare) 274 275 out, _ := dockerCmd(c, "run", "-tid", "--restart=always", "busybox", "sh") 276 id := strings.TrimSpace(string(out)) 277 dockerCmd(c, "update", "--cpu-shares", "512", id) 278 279 cpty, tty, err := pty.Open() 280 c.Assert(err, checker.IsNil) 281 defer cpty.Close() 282 283 cmd := exec.Command(dockerBinary, "attach", id) 284 cmd.Stdin = tty 285 286 c.Assert(cmd.Start(), checker.IsNil) 287 defer cmd.Process.Kill() 288 289 _, err = cpty.Write([]byte("exit\n")) 290 c.Assert(err, checker.IsNil) 291 292 c.Assert(cmd.Wait(), checker.IsNil) 293 294 // container should restart again and keep running 295 err = waitInspect(id, "{{.RestartCount}}", "1", 30*time.Second) 296 c.Assert(err, checker.IsNil) 297 c.Assert(waitRun(id), checker.IsNil) 298 } 299 300 func (s *DockerSuite) TestUpdateWithNanoCPUs(c *check.C) { 301 testRequires(c, cpuCfsQuota, cpuCfsPeriod) 302 303 file1 := "/sys/fs/cgroup/cpu/cpu.cfs_quota_us" 304 file2 := "/sys/fs/cgroup/cpu/cpu.cfs_period_us" 305 306 out, _ := dockerCmd(c, "run", "-d", "--cpus", "0.5", "--name", "top", "busybox", "top") 307 c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") 308 309 out, _ = dockerCmd(c, "exec", "top", "sh", "-c", fmt.Sprintf("cat %s && cat %s", file1, file2)) 310 c.Assert(strings.TrimSpace(out), checker.Equals, "50000\n100000") 311 312 clt, err := client.NewEnvClient() 313 c.Assert(err, checker.IsNil) 314 inspect, err := clt.ContainerInspect(context.Background(), "top") 315 c.Assert(err, checker.IsNil) 316 c.Assert(inspect.HostConfig.NanoCPUs, checker.Equals, int64(500000000)) 317 318 out = inspectField(c, "top", "HostConfig.CpuQuota") 319 c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS quota should be 0")) 320 out = inspectField(c, "top", "HostConfig.CpuPeriod") 321 c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS period should be 0")) 322 323 out, _, err = dockerCmdWithError("update", "--cpu-quota", "80000", "top") 324 c.Assert(err, checker.NotNil) 325 c.Assert(out, checker.Contains, "Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set") 326 327 out, _ = dockerCmd(c, "update", "--cpus", "0.8", "top") 328 inspect, err = clt.ContainerInspect(context.Background(), "top") 329 c.Assert(err, checker.IsNil) 330 c.Assert(inspect.HostConfig.NanoCPUs, checker.Equals, int64(800000000)) 331 332 out = inspectField(c, "top", "HostConfig.CpuQuota") 333 c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS quota should be 0")) 334 out = inspectField(c, "top", "HostConfig.CpuPeriod") 335 c.Assert(out, checker.Equals, "0", check.Commentf("CPU CFS period should be 0")) 336 337 out, _ = dockerCmd(c, "exec", "top", "sh", "-c", fmt.Sprintf("cat %s && cat %s", file1, file2)) 338 c.Assert(strings.TrimSpace(out), checker.Equals, "80000\n100000") 339 }