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  }