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