update_linux_test.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package container // import "github.com/docker/docker/integration/container"
  2. import (
  3. "bytes"
  4. "context"
  5. "io/ioutil"
  6. "strconv"
  7. "strings"
  8. "testing"
  9. "time"
  10. "github.com/docker/docker/api/types"
  11. containertypes "github.com/docker/docker/api/types/container"
  12. "github.com/docker/docker/api/types/strslice"
  13. "github.com/docker/docker/client"
  14. "github.com/docker/docker/integration/internal/container"
  15. "github.com/docker/docker/integration/internal/request"
  16. "github.com/docker/docker/pkg/stdcopy"
  17. "github.com/gotestyourself/gotestyourself/poll"
  18. "github.com/gotestyourself/gotestyourself/skip"
  19. "github.com/stretchr/testify/assert"
  20. "github.com/stretchr/testify/require"
  21. )
  22. func TestUpdateMemory(t *testing.T) {
  23. skip.If(t, testEnv.DaemonInfo.OSType != "linux")
  24. skip.If(t, !testEnv.DaemonInfo.MemoryLimit)
  25. skip.If(t, !testEnv.DaemonInfo.SwapLimit)
  26. defer setupTest(t)()
  27. client := request.NewAPIClient(t)
  28. ctx := context.Background()
  29. cID := container.Run(t, ctx, client, func(c *container.TestContainerConfig) {
  30. c.HostConfig.Resources = containertypes.Resources{
  31. Memory: 200 * 1024 * 1024,
  32. }
  33. })
  34. poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
  35. _, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
  36. Resources: containertypes.Resources{
  37. Memory: 314572800,
  38. MemorySwap: 524288000,
  39. },
  40. })
  41. require.NoError(t, err)
  42. inspect, err := client.ContainerInspect(ctx, cID)
  43. require.NoError(t, err)
  44. assert.Equal(t, inspect.HostConfig.Memory, int64(314572800))
  45. assert.Equal(t, inspect.HostConfig.MemorySwap, int64(524288000))
  46. body, err := getContainerSysFSValue(ctx, client, cID, "/sys/fs/cgroup/memory/memory.limit_in_bytes")
  47. require.NoError(t, err)
  48. assert.Equal(t, strings.TrimSpace(body), "314572800")
  49. body, err = getContainerSysFSValue(ctx, client, cID, "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes")
  50. require.NoError(t, err)
  51. assert.Equal(t, strings.TrimSpace(body), "524288000")
  52. }
  53. func TestUpdateCPUQUota(t *testing.T) {
  54. t.Parallel()
  55. defer setupTest(t)()
  56. client := request.NewAPIClient(t)
  57. ctx := context.Background()
  58. cID := container.Run(t, ctx, client)
  59. for _, test := range []struct {
  60. desc string
  61. update int64
  62. }{
  63. {desc: "some random value", update: 15000},
  64. {desc: "a higher value", update: 20000},
  65. {desc: "a lower value", update: 10000},
  66. {desc: "unset value", update: -1},
  67. } {
  68. if _, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
  69. Resources: containertypes.Resources{
  70. CPUQuota: test.update,
  71. },
  72. }); err != nil {
  73. t.Fatal(err)
  74. }
  75. inspect, err := client.ContainerInspect(ctx, cID)
  76. if err != nil {
  77. t.Fatal(err)
  78. }
  79. if inspect.HostConfig.CPUQuota != test.update {
  80. t.Fatalf("quota not updated in the API, expected %d, got: %d", test.update, inspect.HostConfig.CPUQuota)
  81. }
  82. execCreate, err := client.ContainerExecCreate(ctx, cID, types.ExecConfig{
  83. Cmd: []string{"/bin/cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"},
  84. AttachStdout: true,
  85. AttachStderr: true,
  86. })
  87. if err != nil {
  88. t.Fatal(err)
  89. }
  90. attach, err := client.ContainerExecAttach(ctx, execCreate.ID, types.ExecStartCheck{})
  91. if err != nil {
  92. t.Fatal(err)
  93. }
  94. if err := client.ContainerExecStart(ctx, execCreate.ID, types.ExecStartCheck{}); err != nil {
  95. t.Fatal(err)
  96. }
  97. buf := bytes.NewBuffer(nil)
  98. ready := make(chan error)
  99. go func() {
  100. _, err := stdcopy.StdCopy(buf, buf, attach.Reader)
  101. ready <- err
  102. }()
  103. select {
  104. case <-time.After(60 * time.Second):
  105. t.Fatal("timeout waiting for exec to complete")
  106. case err := <-ready:
  107. if err != nil {
  108. t.Fatal(err)
  109. }
  110. }
  111. actual := strings.TrimSpace(buf.String())
  112. if actual != strconv.Itoa(int(test.update)) {
  113. t.Fatalf("expected cgroup value %d, got: %s", test.update, actual)
  114. }
  115. }
  116. }
  117. func getContainerSysFSValue(ctx context.Context, client client.APIClient, cID string, path string) (string, error) {
  118. var b bytes.Buffer
  119. ex, err := client.ContainerExecCreate(ctx, cID,
  120. types.ExecConfig{
  121. AttachStdout: true,
  122. Cmd: strslice.StrSlice([]string{"cat", path}),
  123. },
  124. )
  125. if err != nil {
  126. return "", err
  127. }
  128. resp, err := client.ContainerExecAttach(ctx, ex.ID,
  129. types.ExecStartCheck{
  130. Detach: false,
  131. Tty: false,
  132. },
  133. )
  134. if err != nil {
  135. return "", err
  136. }
  137. defer resp.Close()
  138. b.Reset()
  139. _, err = stdcopy.StdCopy(&b, ioutil.Discard, resp.Reader)
  140. return b.String(), err
  141. }