github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/integration-cli/docker_cli_update_unix_test.go (about)

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