gopkg.in/docker/docker.v20@v20.10.27/integration-cli/docker_cli_update_unix_test.go (about) 1 //go:build !windows 2 // +build !windows 3 4 package main 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 "os/exec" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/creack/pty" 16 "github.com/docker/docker/api/types" 17 "github.com/docker/docker/client" 18 "github.com/docker/docker/testutil/request" 19 "gotest.tools/v3/assert" 20 ) 21 22 func (s *DockerSuite) TestUpdateRunningContainer(c *testing.T) { 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 assert.Equal(c, inspectField(c, name, "HostConfig.Memory"), "524288000") 31 32 file := "/sys/fs/cgroup/memory/memory.limit_in_bytes" 33 out, _ := dockerCmd(c, "exec", name, "cat", file) 34 assert.Equal(c, strings.TrimSpace(out), "524288000") 35 } 36 37 func (s *DockerSuite) TestUpdateRunningContainerWithRestart(c *testing.T) { 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 assert.Equal(c, inspectField(c, name, "HostConfig.Memory"), "524288000") 47 48 file := "/sys/fs/cgroup/memory/memory.limit_in_bytes" 49 out, _ := dockerCmd(c, "exec", name, "cat", file) 50 assert.Equal(c, strings.TrimSpace(out), "524288000") 51 } 52 53 func (s *DockerSuite) TestUpdateStoppedContainer(c *testing.T) { 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 assert.Equal(c, inspectField(c, name, "HostConfig.Memory"), "524288000") 63 64 out, _ := dockerCmd(c, "start", "-a", name) 65 assert.Equal(c, strings.TrimSpace(out), "524288000") 66 } 67 68 func (s *DockerSuite) TestUpdatePausedContainer(c *testing.T) { 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 assert.Equal(c, inspectField(c, name, "HostConfig.CPUShares"), "500") 78 79 dockerCmd(c, "unpause", name) 80 file := "/sys/fs/cgroup/cpu/cpu.shares" 81 out, _ := dockerCmd(c, "exec", name, "cat", file) 82 assert.Equal(c, strings.TrimSpace(out), "500") 83 } 84 85 func (s *DockerSuite) TestUpdateWithUntouchedFields(c *testing.T) { 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 assert.Equal(c, out, "800") 97 98 file := "/sys/fs/cgroup/cpu/cpu.shares" 99 out, _ = dockerCmd(c, "exec", name, "cat", file) 100 assert.Equal(c, strings.TrimSpace(out), "800") 101 } 102 103 func (s *DockerSuite) TestUpdateContainerInvalidValue(c *testing.T) { 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 assert.ErrorContains(c, err, "") 111 expected := "Minimum memory limit allowed is 6MB" 112 assert.Assert(c, strings.Contains(out, expected)) 113 } 114 115 func (s *DockerSuite) TestUpdateContainerWithoutFlags(c *testing.T) { 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 assert.ErrorContains(c, err, "") 123 } 124 125 func (s *DockerSuite) TestUpdateSwapMemoryOnly(c *testing.T) { 126 testRequires(c, DaemonIsLinux) 127 testRequires(c, memoryLimitSupport) 128 testRequires(c, swapMemorySupport) 129 130 name := "test-update-container" 131 dockerCmd(c, "run", "-d", "--name", name, "--memory", "300M", "--memory-swap", "500M", "busybox", "top") 132 dockerCmd(c, "update", "--memory-swap", "600M", name) 133 134 assert.Equal(c, inspectField(c, name, "HostConfig.MemorySwap"), "629145600") 135 136 file := "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes" 137 out, _ := dockerCmd(c, "exec", name, "cat", file) 138 assert.Equal(c, strings.TrimSpace(out), "629145600") 139 } 140 141 func (s *DockerSuite) TestUpdateInvalidSwapMemory(c *testing.T) { 142 testRequires(c, DaemonIsLinux) 143 testRequires(c, memoryLimitSupport) 144 testRequires(c, swapMemorySupport) 145 146 name := "test-update-container" 147 dockerCmd(c, "run", "-d", "--name", name, "--memory", "300M", "--memory-swap", "500M", "busybox", "top") 148 _, _, err := dockerCmdWithError("update", "--memory-swap", "200M", name) 149 // Update invalid swap memory should fail. 150 // This will pass docker config validation, but failed at kernel validation 151 assert.ErrorContains(c, err, "") 152 153 // Update invalid swap memory with failure should not change HostConfig 154 assert.Equal(c, inspectField(c, name, "HostConfig.Memory"), "314572800") 155 assert.Equal(c, inspectField(c, name, "HostConfig.MemorySwap"), "524288000") 156 157 dockerCmd(c, "update", "--memory-swap", "600M", name) 158 159 assert.Equal(c, inspectField(c, name, "HostConfig.MemorySwap"), "629145600") 160 161 file := "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes" 162 out, _ := dockerCmd(c, "exec", name, "cat", file) 163 assert.Equal(c, strings.TrimSpace(out), "629145600") 164 } 165 166 func (s *DockerSuite) TestUpdateStats(c *testing.T) { 167 testRequires(c, DaemonIsLinux) 168 testRequires(c, memoryLimitSupport) 169 testRequires(c, cpuCfsQuota) 170 name := "foo" 171 dockerCmd(c, "run", "-d", "-ti", "--name", name, "-m", "500m", "busybox") 172 173 assert.NilError(c, waitRun(name)) 174 175 getMemLimit := func(id string) uint64 { 176 resp, body, err := request.Get(fmt.Sprintf("/containers/%s/stats?stream=false", id)) 177 assert.NilError(c, err) 178 assert.Equal(c, resp.Header.Get("Content-Type"), "application/json") 179 180 var v *types.Stats 181 err = json.NewDecoder(body).Decode(&v) 182 assert.NilError(c, err) 183 body.Close() 184 185 return v.MemoryStats.Limit 186 } 187 preMemLimit := getMemLimit(name) 188 189 dockerCmd(c, "update", "--cpu-quota", "2000", name) 190 191 curMemLimit := getMemLimit(name) 192 assert.Equal(c, preMemLimit, curMemLimit) 193 } 194 195 func (s *DockerSuite) TestUpdateMemoryWithSwapMemory(c *testing.T) { 196 testRequires(c, DaemonIsLinux) 197 testRequires(c, memoryLimitSupport) 198 testRequires(c, swapMemorySupport) 199 200 name := "test-update-container" 201 dockerCmd(c, "run", "-d", "--name", name, "--memory", "300M", "busybox", "top") 202 out, _, err := dockerCmdWithError("update", "--memory", "800M", name) 203 assert.ErrorContains(c, err, "") 204 assert.Assert(c, strings.Contains(out, "Memory limit should be smaller than already set memoryswap limit")) 205 206 dockerCmd(c, "update", "--memory", "800M", "--memory-swap", "1000M", name) 207 } 208 209 func (s *DockerSuite) TestUpdateNotAffectMonitorRestartPolicy(c *testing.T) { 210 testRequires(c, DaemonIsLinux, cpuShare) 211 212 out, _ := dockerCmd(c, "run", "-tid", "--restart=always", "busybox", "sh") 213 id := strings.TrimSpace(out) 214 dockerCmd(c, "update", "--cpu-shares", "512", id) 215 216 cpty, tty, err := pty.Open() 217 assert.NilError(c, err) 218 defer cpty.Close() 219 220 cmd := exec.Command(dockerBinary, "attach", id) 221 cmd.Stdin = tty 222 223 assert.NilError(c, cmd.Start()) 224 defer cmd.Process.Kill() 225 226 _, err = cpty.Write([]byte("exit\n")) 227 assert.NilError(c, err) 228 229 assert.NilError(c, cmd.Wait()) 230 231 // container should restart again and keep running 232 err = waitInspect(id, "{{.RestartCount}}", "1", 30*time.Second) 233 assert.NilError(c, err) 234 assert.NilError(c, waitRun(id)) 235 } 236 237 func (s *DockerSuite) TestUpdateWithNanoCPUs(c *testing.T) { 238 testRequires(c, cpuCfsQuota, cpuCfsPeriod) 239 240 file1 := "/sys/fs/cgroup/cpu/cpu.cfs_quota_us" 241 file2 := "/sys/fs/cgroup/cpu/cpu.cfs_period_us" 242 243 out, _ := dockerCmd(c, "run", "-d", "--cpus", "0.5", "--name", "top", "busybox", "top") 244 assert.Assert(c, strings.TrimSpace(out) != "") 245 246 out, _ = dockerCmd(c, "exec", "top", "sh", "-c", fmt.Sprintf("cat %s && cat %s", file1, file2)) 247 assert.Equal(c, strings.TrimSpace(out), "50000\n100000") 248 249 clt, err := client.NewClientWithOpts(client.FromEnv) 250 assert.NilError(c, err) 251 inspect, err := clt.ContainerInspect(context.Background(), "top") 252 assert.NilError(c, err) 253 assert.Equal(c, inspect.HostConfig.NanoCPUs, int64(500000000)) 254 255 out = inspectField(c, "top", "HostConfig.CpuQuota") 256 assert.Equal(c, out, "0", "CPU CFS quota should be 0") 257 out = inspectField(c, "top", "HostConfig.CpuPeriod") 258 assert.Equal(c, out, "0", "CPU CFS period should be 0") 259 260 out, _, err = dockerCmdWithError("update", "--cpu-quota", "80000", "top") 261 assert.ErrorContains(c, err, "") 262 assert.Assert(c, strings.Contains(out, "Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set")) 263 264 dockerCmd(c, "update", "--cpus", "0.8", "top") 265 inspect, err = clt.ContainerInspect(context.Background(), "top") 266 assert.NilError(c, err) 267 assert.Equal(c, inspect.HostConfig.NanoCPUs, int64(800000000)) 268 269 out = inspectField(c, "top", "HostConfig.CpuQuota") 270 assert.Equal(c, out, "0", "CPU CFS quota should be 0") 271 out = inspectField(c, "top", "HostConfig.CpuPeriod") 272 assert.Equal(c, out, "0", "CPU CFS period should be 0") 273 274 out, _ = dockerCmd(c, "exec", "top", "sh", "-c", fmt.Sprintf("cat %s && cat %s", file1, file2)) 275 assert.Equal(c, strings.TrimSpace(out), "80000\n100000") 276 }