Browse code

Restore container configs when update failed

Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>

Qiang Huang authored on 2016/02/24 15:23:48
Showing 2 changed files
... ...
@@ -45,6 +45,17 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro
45 45
 		return err
46 46
 	}
47 47
 
48
+	restoreConfig := false
49
+	backupHostConfig := *container.HostConfig
50
+	defer func() {
51
+		if restoreConfig {
52
+			container.Lock()
53
+			container.HostConfig = &backupHostConfig
54
+			container.ToDisk()
55
+			container.Unlock()
56
+		}
57
+	}()
58
+
48 59
 	if container.RemovalInProgress || container.Dead {
49 60
 		errMsg := fmt.Errorf("Container is marked for removal and cannot be \"update\".")
50 61
 		return derr.ErrorCodeCantUpdate.WithArgs(container.ID, errMsg)
... ...
@@ -56,6 +67,7 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro
56 56
 	}
57 57
 
58 58
 	if err := container.UpdateContainer(hostConfig); err != nil {
59
+		restoreConfig = true
59 60
 		return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error())
60 61
 	}
61 62
 
... ...
@@ -73,6 +85,7 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro
73 73
 	// to the real world.
74 74
 	if container.IsRunning() && !container.IsRestarting() {
75 75
 		if err := daemon.execDriver.Update(container.Command); err != nil {
76
+			restoreConfig = true
76 77
 			return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error())
77 78
 		}
78 79
 	}
... ...
@@ -155,6 +155,31 @@ func (s *DockerSuite) TestUpdateSwapMemoryOnly(c *check.C) {
155 155
 	c.Assert(strings.TrimSpace(out), checker.Equals, "629145600")
156 156
 }
157 157
 
158
+func (s *DockerSuite) TestUpdateInvalidSwapMemory(c *check.C) {
159
+	testRequires(c, DaemonIsLinux)
160
+	testRequires(c, memoryLimitSupport)
161
+	testRequires(c, swapMemorySupport)
162
+
163
+	name := "test-update-container"
164
+	dockerCmd(c, "run", "-d", "--name", name, "--memory", "300M", "--memory-swap", "500M", "busybox", "top")
165
+	_, _, err := dockerCmdWithError("update", "--memory-swap", "200M", name)
166
+	// Update invalid swap memory should fail.
167
+	// This will pass docker config validation, but failed at kernel validation
168
+	c.Assert(err, check.NotNil)
169
+
170
+	// Update invalid swap memory with failure should not change HostConfig
171
+	c.Assert(inspectField(c, name, "HostConfig.Memory"), checker.Equals, "314572800")
172
+	c.Assert(inspectField(c, name, "HostConfig.MemorySwap"), checker.Equals, "524288000")
173
+
174
+	dockerCmd(c, "update", "--memory-swap", "600M", name)
175
+
176
+	c.Assert(inspectField(c, name, "HostConfig.MemorySwap"), checker.Equals, "629145600")
177
+
178
+	file := "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"
179
+	out, _ := dockerCmd(c, "exec", name, "cat", file)
180
+	c.Assert(strings.TrimSpace(out), checker.Equals, "629145600")
181
+}
182
+
158 183
 func (s *DockerSuite) TestUpdateStats(c *check.C) {
159 184
 	testRequires(c, DaemonIsLinux)
160 185
 	testRequires(c, memoryLimitSupport)