Signed-off-by: Fabio Kung <fabio.kung@gmail.com>
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package container |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "bytes" |
|
| 4 | 5 |
"encoding/json" |
| 5 | 6 |
"fmt" |
| 6 | 7 |
"io" |
| ... | ... |
@@ -14,8 +15,6 @@ import ( |
| 14 | 14 |
"syscall" |
| 15 | 15 |
"time" |
| 16 | 16 |
|
| 17 |
- "golang.org/x/net/context" |
|
| 18 |
- |
|
| 19 | 17 |
"github.com/Sirupsen/logrus" |
| 20 | 18 |
containertypes "github.com/docker/docker/api/types/container" |
| 21 | 19 |
mounttypes "github.com/docker/docker/api/types/mount" |
| ... | ... |
@@ -45,6 +44,7 @@ import ( |
| 45 | 45 |
"github.com/docker/libnetwork/options" |
| 46 | 46 |
"github.com/docker/libnetwork/types" |
| 47 | 47 |
agentexec "github.com/docker/swarmkit/agent/exec" |
| 48 |
+ "golang.org/x/net/context" |
|
| 48 | 49 |
) |
| 49 | 50 |
|
| 50 | 51 |
const configFileName = "config.v2.json" |
| ... | ... |
@@ -154,36 +154,48 @@ func (container *Container) FromDisk() error {
|
| 154 | 154 |
return container.readHostConfig() |
| 155 | 155 |
} |
| 156 | 156 |
|
| 157 |
-// ToDisk saves the container configuration on disk. |
|
| 158 |
-func (container *Container) toDisk() error {
|
|
| 157 |
+// toDisk saves the container configuration on disk and returns a deep copy. |
|
| 158 |
+func (container *Container) toDisk() (*Container, error) {
|
|
| 159 |
+ var ( |
|
| 160 |
+ buf bytes.Buffer |
|
| 161 |
+ deepCopy Container |
|
| 162 |
+ ) |
|
| 159 | 163 |
pth, err := container.ConfigPath() |
| 160 | 164 |
if err != nil {
|
| 161 |
- return err |
|
| 165 |
+ return nil, err |
|
| 162 | 166 |
} |
| 163 | 167 |
|
| 164 |
- jsonSource, err := ioutils.NewAtomicFileWriter(pth, 0644) |
|
| 168 |
+ // Save container settings |
|
| 169 |
+ f, err := ioutils.NewAtomicFileWriter(pth, 0644) |
|
| 165 | 170 |
if err != nil {
|
| 166 |
- return err |
|
| 171 |
+ return nil, err |
|
| 167 | 172 |
} |
| 168 |
- defer jsonSource.Close() |
|
| 173 |
+ defer f.Close() |
|
| 169 | 174 |
|
| 170 |
- enc := json.NewEncoder(jsonSource) |
|
| 175 |
+ w := io.MultiWriter(&buf, f) |
|
| 176 |
+ if err := json.NewEncoder(w).Encode(container); err != nil {
|
|
| 177 |
+ return nil, err |
|
| 178 |
+ } |
|
| 171 | 179 |
|
| 172 |
- // Save container settings |
|
| 173 |
- if err := enc.Encode(container); err != nil {
|
|
| 174 |
- return err |
|
| 180 |
+ if err := json.NewDecoder(&buf).Decode(&deepCopy); err != nil {
|
|
| 181 |
+ return nil, err |
|
| 182 |
+ } |
|
| 183 |
+ deepCopy.HostConfig, err = container.WriteHostConfig() |
|
| 184 |
+ if err != nil {
|
|
| 185 |
+ return nil, err |
|
| 175 | 186 |
} |
| 176 | 187 |
|
| 177 |
- return container.WriteHostConfig() |
|
| 188 |
+ return &deepCopy, nil |
|
| 178 | 189 |
} |
| 179 | 190 |
|
| 180 | 191 |
// CheckpointTo makes the Container's current state visible to queries, and persists state. |
| 181 | 192 |
// Callers must hold a Container lock. |
| 182 | 193 |
func (container *Container) CheckpointTo(store ViewDB) error {
|
| 183 |
- if err := container.toDisk(); err != nil {
|
|
| 194 |
+ deepCopy, err := container.toDisk() |
|
| 195 |
+ if err != nil {
|
|
| 184 | 196 |
return err |
| 185 | 197 |
} |
| 186 |
- return store.Save(container) |
|
| 198 |
+ return store.Save(deepCopy) |
|
| 187 | 199 |
} |
| 188 | 200 |
|
| 189 | 201 |
// readHostConfig reads the host configuration from disk for the container. |
| ... | ... |
@@ -215,20 +227,34 @@ func (container *Container) readHostConfig() error {
|
| 215 | 215 |
return nil |
| 216 | 216 |
} |
| 217 | 217 |
|
| 218 |
-// WriteHostConfig saves the host configuration on disk for the container. |
|
| 219 |
-func (container *Container) WriteHostConfig() error {
|
|
| 218 |
+// WriteHostConfig saves the host configuration on disk for the container, |
|
| 219 |
+// and returns a deep copy of the saved object. Callers must hold a Container lock. |
|
| 220 |
+func (container *Container) WriteHostConfig() (*containertypes.HostConfig, error) {
|
|
| 221 |
+ var ( |
|
| 222 |
+ buf bytes.Buffer |
|
| 223 |
+ deepCopy containertypes.HostConfig |
|
| 224 |
+ ) |
|
| 225 |
+ |
|
| 220 | 226 |
pth, err := container.HostConfigPath() |
| 221 | 227 |
if err != nil {
|
| 222 |
- return err |
|
| 228 |
+ return nil, err |
|
| 223 | 229 |
} |
| 224 | 230 |
|
| 225 | 231 |
f, err := ioutils.NewAtomicFileWriter(pth, 0644) |
| 226 | 232 |
if err != nil {
|
| 227 |
- return err |
|
| 233 |
+ return nil, err |
|
| 228 | 234 |
} |
| 229 | 235 |
defer f.Close() |
| 230 | 236 |
|
| 231 |
- return json.NewEncoder(f).Encode(&container.HostConfig) |
|
| 237 |
+ w := io.MultiWriter(&buf, f) |
|
| 238 |
+ if err := json.NewEncoder(w).Encode(&container.HostConfig); err != nil {
|
|
| 239 |
+ return nil, err |
|
| 240 |
+ } |
|
| 241 |
+ |
|
| 242 |
+ if err := json.NewDecoder(&buf).Decode(&deepCopy); err != nil {
|
|
| 243 |
+ return nil, err |
|
| 244 |
+ } |
|
| 245 |
+ return &deepCopy, nil |
|
| 232 | 246 |
} |
| 233 | 247 |
|
| 234 | 248 |
// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir |
| ... | ... |
@@ -90,16 +90,12 @@ func (db *memDB) Snapshot(index *registrar.Registrar) View {
|
| 90 | 90 |
} |
| 91 | 91 |
} |
| 92 | 92 |
|
| 93 |
-// Save atomically updates the in-memory store from the current on-disk state of a Container. |
|
| 93 |
+// Save atomically updates the in-memory store state for a Container. |
|
| 94 |
+// Only read only (deep) copies of containers may be passed in. |
|
| 94 | 95 |
func (db *memDB) Save(c *Container) error {
|
| 95 | 96 |
txn := db.store.Txn(true) |
| 96 | 97 |
defer txn.Commit() |
| 97 |
- deepCopy := NewBaseContainer(c.ID, c.Root) |
|
| 98 |
- err := deepCopy.FromDisk() |
|
| 99 |
- if err != nil {
|
|
| 100 |
- return err |
|
| 101 |
- } |
|
| 102 |
- return txn.Insert(memdbTable, deepCopy) |
|
| 98 |
+ return txn.Insert(memdbTable, c) |
|
| 103 | 99 |
} |
| 104 | 100 |
|
| 105 | 101 |
// Delete removes an item by ID |
| ... | ... |
@@ -579,7 +579,7 @@ func (daemon *Daemon) allocateNetwork(container *container.Container) error {
|
| 579 | 579 |
|
| 580 | 580 |
} |
| 581 | 581 |
|
| 582 |
- if err := container.WriteHostConfig(); err != nil {
|
|
| 582 |
+ if _, err := container.WriteHostConfig(); err != nil {
|
|
| 583 | 583 |
return err |
| 584 | 584 |
} |
| 585 | 585 |
networkActions.WithValues("allocate").UpdateSince(start)
|
| ... | ... |
@@ -1146,7 +1146,8 @@ func (daemon *Daemon) registerLinks(container *container.Container, hostConfig * |
| 1146 | 1146 |
|
| 1147 | 1147 |
// After we load all the links into the daemon |
| 1148 | 1148 |
// set them to nil on the hostconfig |
| 1149 |
- return container.WriteHostConfig() |
|
| 1149 |
+ _, err := container.WriteHostConfig() |
|
| 1150 |
+ return err |
|
| 1150 | 1151 |
} |
| 1151 | 1152 |
|
| 1152 | 1153 |
// conditionalMountOnStart is a platform specific helper function during the |