Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Vincent Demeester authored on 2016/05/25 00:49:2616 | 16 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,145 @@ |
0 |
+package daemon |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "fmt" |
|
4 |
+ "path/filepath" |
|
5 |
+ "time" |
|
6 |
+ |
|
7 |
+ "github.com/docker/docker/container" |
|
8 |
+ "github.com/docker/docker/daemon/network" |
|
9 |
+ "github.com/docker/docker/errors" |
|
10 |
+ "github.com/docker/docker/image" |
|
11 |
+ "github.com/docker/docker/pkg/truncindex" |
|
12 |
+ containertypes "github.com/docker/engine-api/types/container" |
|
13 |
+) |
|
14 |
+ |
|
15 |
+// GetContainer looks for a container using the provided information, which could be |
|
16 |
+// one of the following inputs from the caller: |
|
17 |
+// - A full container ID, which will exact match a container in daemon's list |
|
18 |
+// - A container name, which will only exact match via the GetByName() function |
|
19 |
+// - A partial container ID prefix (e.g. short ID) of any length that is |
|
20 |
+// unique enough to only return a single container object |
|
21 |
+// If none of these searches succeed, an error is returned |
|
22 |
+func (daemon *Daemon) GetContainer(prefixOrName string) (*container.Container, error) { |
|
23 |
+ if len(prefixOrName) == 0 { |
|
24 |
+ return nil, errors.NewBadRequestError(fmt.Errorf("No container name or ID supplied")) |
|
25 |
+ } |
|
26 |
+ |
|
27 |
+ if containerByID := daemon.containers.Get(prefixOrName); containerByID != nil { |
|
28 |
+ // prefix is an exact match to a full container ID |
|
29 |
+ return containerByID, nil |
|
30 |
+ } |
|
31 |
+ |
|
32 |
+ // GetByName will match only an exact name provided; we ignore errors |
|
33 |
+ if containerByName, _ := daemon.GetByName(prefixOrName); containerByName != nil { |
|
34 |
+ // prefix is an exact match to a full container Name |
|
35 |
+ return containerByName, nil |
|
36 |
+ } |
|
37 |
+ |
|
38 |
+ containerID, indexError := daemon.idIndex.Get(prefixOrName) |
|
39 |
+ if indexError != nil { |
|
40 |
+ // When truncindex defines an error type, use that instead |
|
41 |
+ if indexError == truncindex.ErrNotExist { |
|
42 |
+ err := fmt.Errorf("No such container: %s", prefixOrName) |
|
43 |
+ return nil, errors.NewRequestNotFoundError(err) |
|
44 |
+ } |
|
45 |
+ return nil, indexError |
|
46 |
+ } |
|
47 |
+ return daemon.containers.Get(containerID), nil |
|
48 |
+} |
|
49 |
+ |
|
50 |
+// Exists returns a true if a container of the specified ID or name exists, |
|
51 |
+// false otherwise. |
|
52 |
+func (daemon *Daemon) Exists(id string) bool { |
|
53 |
+ c, _ := daemon.GetContainer(id) |
|
54 |
+ return c != nil |
|
55 |
+} |
|
56 |
+ |
|
57 |
+// IsPaused returns a bool indicating if the specified container is paused. |
|
58 |
+func (daemon *Daemon) IsPaused(id string) bool { |
|
59 |
+ c, _ := daemon.GetContainer(id) |
|
60 |
+ return c.State.IsPaused() |
|
61 |
+} |
|
62 |
+ |
|
63 |
+func (daemon *Daemon) containerRoot(id string) string { |
|
64 |
+ return filepath.Join(daemon.repository, id) |
|
65 |
+} |
|
66 |
+ |
|
67 |
+// Load reads the contents of a container from disk |
|
68 |
+// This is typically done at startup. |
|
69 |
+func (daemon *Daemon) load(id string) (*container.Container, error) { |
|
70 |
+ container := daemon.newBaseContainer(id) |
|
71 |
+ |
|
72 |
+ if err := container.FromDisk(); err != nil { |
|
73 |
+ return nil, err |
|
74 |
+ } |
|
75 |
+ |
|
76 |
+ if container.ID != id { |
|
77 |
+ return container, fmt.Errorf("Container %s is stored at %s", container.ID, id) |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ return container, nil |
|
81 |
+} |
|
82 |
+ |
|
83 |
+// Register makes a container object usable by the daemon as <container.ID> |
|
84 |
+func (daemon *Daemon) Register(c *container.Container) error { |
|
85 |
+ // Attach to stdout and stderr |
|
86 |
+ if c.Config.OpenStdin { |
|
87 |
+ c.NewInputPipes() |
|
88 |
+ } else { |
|
89 |
+ c.NewNopInputPipe() |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ daemon.containers.Add(c.ID, c) |
|
93 |
+ daemon.idIndex.Add(c.ID) |
|
94 |
+ |
|
95 |
+ return nil |
|
96 |
+} |
|
97 |
+ |
|
98 |
+func (daemon *Daemon) newContainer(name string, config *containertypes.Config, imgID image.ID) (*container.Container, error) { |
|
99 |
+ var ( |
|
100 |
+ id string |
|
101 |
+ err error |
|
102 |
+ noExplicitName = name == "" |
|
103 |
+ ) |
|
104 |
+ id, name, err = daemon.generateIDAndName(name) |
|
105 |
+ if err != nil { |
|
106 |
+ return nil, err |
|
107 |
+ } |
|
108 |
+ |
|
109 |
+ daemon.generateHostname(id, config) |
|
110 |
+ entrypoint, args := daemon.getEntrypointAndArgs(config.Entrypoint, config.Cmd) |
|
111 |
+ |
|
112 |
+ base := daemon.newBaseContainer(id) |
|
113 |
+ base.Created = time.Now().UTC() |
|
114 |
+ base.Path = entrypoint |
|
115 |
+ base.Args = args //FIXME: de-duplicate from config |
|
116 |
+ base.Config = config |
|
117 |
+ base.HostConfig = &containertypes.HostConfig{} |
|
118 |
+ base.ImageID = imgID |
|
119 |
+ base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName} |
|
120 |
+ base.Name = name |
|
121 |
+ base.Driver = daemon.GraphDriverName() |
|
122 |
+ |
|
123 |
+ return base, err |
|
124 |
+} |
|
125 |
+ |
|
126 |
+// GetByName returns a container given a name. |
|
127 |
+func (daemon *Daemon) GetByName(name string) (*container.Container, error) { |
|
128 |
+ if len(name) == 0 { |
|
129 |
+ return nil, fmt.Errorf("No container name supplied") |
|
130 |
+ } |
|
131 |
+ fullName := name |
|
132 |
+ if name[0] != '/' { |
|
133 |
+ fullName = "/" + name |
|
134 |
+ } |
|
135 |
+ id, err := daemon.nameIndex.Get(fullName) |
|
136 |
+ if err != nil { |
|
137 |
+ return nil, fmt.Errorf("Could not find entity for %s", name) |
|
138 |
+ } |
|
139 |
+ e := daemon.containers.Get(id) |
|
140 |
+ if e == nil { |
|
141 |
+ return nil, fmt.Errorf("Could not find container for entity id %s", id) |
|
142 |
+ } |
|
143 |
+ return e, nil |
|
144 |
+} |
... | ... |
@@ -218,3 +218,15 @@ func (daemon *Daemon) VolumeCreate(name, driverName string, opts, labels map[str |
218 | 218 |
apiV.Mountpoint = v.Path() |
219 | 219 |
return apiV, nil |
220 | 220 |
} |
221 |
+ |
|
222 |
+func (daemon *Daemon) mergeAndVerifyConfig(config *containertypes.Config, img *image.Image) error { |
|
223 |
+ if img != nil && img.Config != nil { |
|
224 |
+ if err := merge(config, img.Config); err != nil { |
|
225 |
+ return err |
|
226 |
+ } |
|
227 |
+ } |
|
228 |
+ if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 { |
|
229 |
+ return fmt.Errorf("No command specified") |
|
230 |
+ } |
|
231 |
+ return nil |
|
232 |
+} |
... | ... |
@@ -36,7 +36,6 @@ import ( |
36 | 36 |
"github.com/docker/engine-api/types/strslice" |
37 | 37 |
// register graph drivers |
38 | 38 |
_ "github.com/docker/docker/daemon/graphdriver/register" |
39 |
- "github.com/docker/docker/daemon/network" |
|
40 | 39 |
dmetadata "github.com/docker/docker/distribution/metadata" |
41 | 40 |
"github.com/docker/docker/distribution/xfer" |
42 | 41 |
"github.com/docker/docker/dockerversion" |
... | ... |
@@ -44,16 +43,13 @@ import ( |
44 | 44 |
"github.com/docker/docker/layer" |
45 | 45 |
"github.com/docker/docker/libcontainerd" |
46 | 46 |
"github.com/docker/docker/migrate/v1" |
47 |
- "github.com/docker/docker/pkg/archive" |
|
48 | 47 |
"github.com/docker/docker/pkg/fileutils" |
49 | 48 |
"github.com/docker/docker/pkg/graphdb" |
50 | 49 |
"github.com/docker/docker/pkg/idtools" |
51 |
- "github.com/docker/docker/pkg/namesgenerator" |
|
52 | 50 |
"github.com/docker/docker/pkg/progress" |
53 | 51 |
"github.com/docker/docker/pkg/registrar" |
54 | 52 |
"github.com/docker/docker/pkg/signal" |
55 | 53 |
"github.com/docker/docker/pkg/streamformatter" |
56 |
- "github.com/docker/docker/pkg/stringid" |
|
57 | 54 |
"github.com/docker/docker/pkg/sysinfo" |
58 | 55 |
"github.com/docker/docker/pkg/system" |
59 | 56 |
"github.com/docker/docker/pkg/truncindex" |
... | ... |
@@ -73,9 +69,6 @@ import ( |
73 | 73 |
) |
74 | 74 |
|
75 | 75 |
var ( |
76 |
- validContainerNameChars = utils.RestrictedNameChars |
|
77 |
- validContainerNamePattern = utils.RestrictedNamePattern |
|
78 |
- |
|
79 | 76 |
errSystemNotSupported = fmt.Errorf("The Docker daemon is not supported on this platform.") |
80 | 77 |
) |
81 | 78 |
|
... | ... |
@@ -112,110 +105,6 @@ type Daemon struct { |
112 | 112 |
defaultIsolation containertypes.Isolation // Default isolation mode on Windows |
113 | 113 |
} |
114 | 114 |
|
115 |
-// GetContainer looks for a container using the provided information, which could be |
|
116 |
-// one of the following inputs from the caller: |
|
117 |
-// - A full container ID, which will exact match a container in daemon's list |
|
118 |
-// - A container name, which will only exact match via the GetByName() function |
|
119 |
-// - A partial container ID prefix (e.g. short ID) of any length that is |
|
120 |
-// unique enough to only return a single container object |
|
121 |
-// If none of these searches succeed, an error is returned |
|
122 |
-func (daemon *Daemon) GetContainer(prefixOrName string) (*container.Container, error) { |
|
123 |
- if len(prefixOrName) == 0 { |
|
124 |
- return nil, errors.NewBadRequestError(fmt.Errorf("No container name or ID supplied")) |
|
125 |
- } |
|
126 |
- |
|
127 |
- if containerByID := daemon.containers.Get(prefixOrName); containerByID != nil { |
|
128 |
- // prefix is an exact match to a full container ID |
|
129 |
- return containerByID, nil |
|
130 |
- } |
|
131 |
- |
|
132 |
- // GetByName will match only an exact name provided; we ignore errors |
|
133 |
- if containerByName, _ := daemon.GetByName(prefixOrName); containerByName != nil { |
|
134 |
- // prefix is an exact match to a full container Name |
|
135 |
- return containerByName, nil |
|
136 |
- } |
|
137 |
- |
|
138 |
- containerID, indexError := daemon.idIndex.Get(prefixOrName) |
|
139 |
- if indexError != nil { |
|
140 |
- // When truncindex defines an error type, use that instead |
|
141 |
- if indexError == truncindex.ErrNotExist { |
|
142 |
- err := fmt.Errorf("No such container: %s", prefixOrName) |
|
143 |
- return nil, errors.NewRequestNotFoundError(err) |
|
144 |
- } |
|
145 |
- return nil, indexError |
|
146 |
- } |
|
147 |
- return daemon.containers.Get(containerID), nil |
|
148 |
-} |
|
149 |
- |
|
150 |
-// Exists returns a true if a container of the specified ID or name exists, |
|
151 |
-// false otherwise. |
|
152 |
-func (daemon *Daemon) Exists(id string) bool { |
|
153 |
- c, _ := daemon.GetContainer(id) |
|
154 |
- return c != nil |
|
155 |
-} |
|
156 |
- |
|
157 |
-// IsPaused returns a bool indicating if the specified container is paused. |
|
158 |
-func (daemon *Daemon) IsPaused(id string) bool { |
|
159 |
- c, _ := daemon.GetContainer(id) |
|
160 |
- return c.State.IsPaused() |
|
161 |
-} |
|
162 |
- |
|
163 |
-func (daemon *Daemon) containerRoot(id string) string { |
|
164 |
- return filepath.Join(daemon.repository, id) |
|
165 |
-} |
|
166 |
- |
|
167 |
-// Load reads the contents of a container from disk |
|
168 |
-// This is typically done at startup. |
|
169 |
-func (daemon *Daemon) load(id string) (*container.Container, error) { |
|
170 |
- container := daemon.newBaseContainer(id) |
|
171 |
- |
|
172 |
- if err := container.FromDisk(); err != nil { |
|
173 |
- return nil, err |
|
174 |
- } |
|
175 |
- |
|
176 |
- if container.ID != id { |
|
177 |
- return container, fmt.Errorf("Container %s is stored at %s", container.ID, id) |
|
178 |
- } |
|
179 |
- |
|
180 |
- return container, nil |
|
181 |
-} |
|
182 |
- |
|
183 |
-func (daemon *Daemon) registerName(container *container.Container) error { |
|
184 |
- if daemon.Exists(container.ID) { |
|
185 |
- return fmt.Errorf("Container is already loaded") |
|
186 |
- } |
|
187 |
- if err := validateID(container.ID); err != nil { |
|
188 |
- return err |
|
189 |
- } |
|
190 |
- if container.Name == "" { |
|
191 |
- name, err := daemon.generateNewName(container.ID) |
|
192 |
- if err != nil { |
|
193 |
- return err |
|
194 |
- } |
|
195 |
- container.Name = name |
|
196 |
- |
|
197 |
- if err := container.ToDiskLocking(); err != nil { |
|
198 |
- logrus.Errorf("Error saving container name to disk: %v", err) |
|
199 |
- } |
|
200 |
- } |
|
201 |
- return daemon.nameIndex.Reserve(container.Name, container.ID) |
|
202 |
-} |
|
203 |
- |
|
204 |
-// Register makes a container object usable by the daemon as <container.ID> |
|
205 |
-func (daemon *Daemon) Register(c *container.Container) error { |
|
206 |
- // Attach to stdout and stderr |
|
207 |
- if c.Config.OpenStdin { |
|
208 |
- c.NewInputPipes() |
|
209 |
- } else { |
|
210 |
- c.NewNopInputPipe() |
|
211 |
- } |
|
212 |
- |
|
213 |
- daemon.containers.Add(c.ID, c) |
|
214 |
- daemon.idIndex.Add(c.ID) |
|
215 |
- |
|
216 |
- return nil |
|
217 |
-} |
|
218 |
- |
|
219 | 115 |
func (daemon *Daemon) restore() error { |
220 | 116 |
var ( |
221 | 117 |
debug = utils.IsDebugEnabled() |
... | ... |
@@ -431,88 +320,6 @@ func (daemon *Daemon) waitForNetworks(c *container.Container) { |
431 | 431 |
} |
432 | 432 |
} |
433 | 433 |
|
434 |
-func (daemon *Daemon) mergeAndVerifyConfig(config *containertypes.Config, img *image.Image) error { |
|
435 |
- if img != nil && img.Config != nil { |
|
436 |
- if err := merge(config, img.Config); err != nil { |
|
437 |
- return err |
|
438 |
- } |
|
439 |
- } |
|
440 |
- if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 { |
|
441 |
- return fmt.Errorf("No command specified") |
|
442 |
- } |
|
443 |
- return nil |
|
444 |
-} |
|
445 |
- |
|
446 |
-func (daemon *Daemon) generateIDAndName(name string) (string, string, error) { |
|
447 |
- var ( |
|
448 |
- err error |
|
449 |
- id = stringid.GenerateNonCryptoID() |
|
450 |
- ) |
|
451 |
- |
|
452 |
- if name == "" { |
|
453 |
- if name, err = daemon.generateNewName(id); err != nil { |
|
454 |
- return "", "", err |
|
455 |
- } |
|
456 |
- return id, name, nil |
|
457 |
- } |
|
458 |
- |
|
459 |
- if name, err = daemon.reserveName(id, name); err != nil { |
|
460 |
- return "", "", err |
|
461 |
- } |
|
462 |
- |
|
463 |
- return id, name, nil |
|
464 |
-} |
|
465 |
- |
|
466 |
-func (daemon *Daemon) reserveName(id, name string) (string, error) { |
|
467 |
- if !validContainerNamePattern.MatchString(name) { |
|
468 |
- return "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars) |
|
469 |
- } |
|
470 |
- if name[0] != '/' { |
|
471 |
- name = "/" + name |
|
472 |
- } |
|
473 |
- |
|
474 |
- if err := daemon.nameIndex.Reserve(name, id); err != nil { |
|
475 |
- if err == registrar.ErrNameReserved { |
|
476 |
- id, err := daemon.nameIndex.Get(name) |
|
477 |
- if err != nil { |
|
478 |
- logrus.Errorf("got unexpected error while looking up reserved name: %v", err) |
|
479 |
- return "", err |
|
480 |
- } |
|
481 |
- return "", fmt.Errorf("Conflict. The name %q is already in use by container %s. You have to remove (or rename) that container to be able to reuse that name.", name, id) |
|
482 |
- } |
|
483 |
- return "", fmt.Errorf("error reserving name: %s, error: %v", name, err) |
|
484 |
- } |
|
485 |
- return name, nil |
|
486 |
-} |
|
487 |
- |
|
488 |
-func (daemon *Daemon) releaseName(name string) { |
|
489 |
- daemon.nameIndex.Release(name) |
|
490 |
-} |
|
491 |
- |
|
492 |
-func (daemon *Daemon) generateNewName(id string) (string, error) { |
|
493 |
- var name string |
|
494 |
- for i := 0; i < 6; i++ { |
|
495 |
- name = namesgenerator.GetRandomName(i) |
|
496 |
- if name[0] != '/' { |
|
497 |
- name = "/" + name |
|
498 |
- } |
|
499 |
- |
|
500 |
- if err := daemon.nameIndex.Reserve(name, id); err != nil { |
|
501 |
- if err == registrar.ErrNameReserved { |
|
502 |
- continue |
|
503 |
- } |
|
504 |
- return "", err |
|
505 |
- } |
|
506 |
- return name, nil |
|
507 |
- } |
|
508 |
- |
|
509 |
- name = "/" + stringid.TruncateID(id) |
|
510 |
- if err := daemon.nameIndex.Reserve(name, id); err != nil { |
|
511 |
- return "", err |
|
512 |
- } |
|
513 |
- return name, nil |
|
514 |
-} |
|
515 |
- |
|
516 | 434 |
func (daemon *Daemon) generateHostname(id string, config *containertypes.Config) { |
517 | 435 |
// Generate default hostname |
518 | 436 |
if config.Hostname == "" { |
... | ... |
@@ -527,54 +334,6 @@ func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint strslice.StrSlice, c |
527 | 527 |
return configCmd[0], configCmd[1:] |
528 | 528 |
} |
529 | 529 |
|
530 |
-func (daemon *Daemon) newContainer(name string, config *containertypes.Config, imgID image.ID) (*container.Container, error) { |
|
531 |
- var ( |
|
532 |
- id string |
|
533 |
- err error |
|
534 |
- noExplicitName = name == "" |
|
535 |
- ) |
|
536 |
- id, name, err = daemon.generateIDAndName(name) |
|
537 |
- if err != nil { |
|
538 |
- return nil, err |
|
539 |
- } |
|
540 |
- |
|
541 |
- daemon.generateHostname(id, config) |
|
542 |
- entrypoint, args := daemon.getEntrypointAndArgs(config.Entrypoint, config.Cmd) |
|
543 |
- |
|
544 |
- base := daemon.newBaseContainer(id) |
|
545 |
- base.Created = time.Now().UTC() |
|
546 |
- base.Path = entrypoint |
|
547 |
- base.Args = args //FIXME: de-duplicate from config |
|
548 |
- base.Config = config |
|
549 |
- base.HostConfig = &containertypes.HostConfig{} |
|
550 |
- base.ImageID = imgID |
|
551 |
- base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName} |
|
552 |
- base.Name = name |
|
553 |
- base.Driver = daemon.GraphDriverName() |
|
554 |
- |
|
555 |
- return base, err |
|
556 |
-} |
|
557 |
- |
|
558 |
-// GetByName returns a container given a name. |
|
559 |
-func (daemon *Daemon) GetByName(name string) (*container.Container, error) { |
|
560 |
- if len(name) == 0 { |
|
561 |
- return nil, fmt.Errorf("No container name supplied") |
|
562 |
- } |
|
563 |
- fullName := name |
|
564 |
- if name[0] != '/' { |
|
565 |
- fullName = "/" + name |
|
566 |
- } |
|
567 |
- id, err := daemon.nameIndex.Get(fullName) |
|
568 |
- if err != nil { |
|
569 |
- return nil, fmt.Errorf("Could not find entity for %s", name) |
|
570 |
- } |
|
571 |
- e := daemon.containers.Get(id) |
|
572 |
- if e == nil { |
|
573 |
- return nil, fmt.Errorf("Could not find container for entity id %s", id) |
|
574 |
- } |
|
575 |
- return e, nil |
|
576 |
-} |
|
577 |
- |
|
578 | 530 |
// GetLabels for a container or image id |
579 | 531 |
func (daemon *Daemon) GetLabels(id string) map[string]string { |
580 | 532 |
// TODO: TestCase |
... | ... |
@@ -947,22 +706,6 @@ func (daemon *Daemon) Unmount(container *container.Container) error { |
947 | 947 |
return nil |
948 | 948 |
} |
949 | 949 |
|
950 |
-func (daemon *Daemon) kill(c *container.Container, sig int) error { |
|
951 |
- return daemon.containerd.Signal(c.ID, sig) |
|
952 |
-} |
|
953 |
- |
|
954 |
-func (daemon *Daemon) subscribeToContainerStats(c *container.Container) chan interface{} { |
|
955 |
- return daemon.statsCollector.collect(c) |
|
956 |
-} |
|
957 |
- |
|
958 |
-func (daemon *Daemon) unsubscribeToContainerStats(c *container.Container, ch chan interface{}) { |
|
959 |
- daemon.statsCollector.unsubscribe(c, ch) |
|
960 |
-} |
|
961 |
- |
|
962 |
-func (daemon *Daemon) changes(container *container.Container) ([]archive.Change, error) { |
|
963 |
- return container.RWLayer.Changes() |
|
964 |
-} |
|
965 |
- |
|
966 | 950 |
func writeDistributionProgress(cancelFunc func(), outStream io.Writer, progressChan <-chan progress.Progress) { |
967 | 951 |
progressOutput := streamformatter.NewJSONStreamFormatter().NewProgressOutput(outStream, false) |
968 | 952 |
operationCancelled := false |
154 | 158 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,108 @@ |
0 |
+package daemon |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "fmt" |
|
4 |
+ |
|
5 |
+ "github.com/Sirupsen/logrus" |
|
6 |
+ "github.com/docker/docker/container" |
|
7 |
+ "github.com/docker/docker/pkg/namesgenerator" |
|
8 |
+ "github.com/docker/docker/pkg/registrar" |
|
9 |
+ "github.com/docker/docker/pkg/stringid" |
|
10 |
+ "github.com/docker/docker/utils" |
|
11 |
+) |
|
12 |
+ |
|
13 |
+var ( |
|
14 |
+ validContainerNameChars = utils.RestrictedNameChars |
|
15 |
+ validContainerNamePattern = utils.RestrictedNamePattern |
|
16 |
+) |
|
17 |
+ |
|
18 |
+func (daemon *Daemon) registerName(container *container.Container) error { |
|
19 |
+ if daemon.Exists(container.ID) { |
|
20 |
+ return fmt.Errorf("Container is already loaded") |
|
21 |
+ } |
|
22 |
+ if err := validateID(container.ID); err != nil { |
|
23 |
+ return err |
|
24 |
+ } |
|
25 |
+ if container.Name == "" { |
|
26 |
+ name, err := daemon.generateNewName(container.ID) |
|
27 |
+ if err != nil { |
|
28 |
+ return err |
|
29 |
+ } |
|
30 |
+ container.Name = name |
|
31 |
+ |
|
32 |
+ if err := container.ToDiskLocking(); err != nil { |
|
33 |
+ logrus.Errorf("Error saving container name to disk: %v", err) |
|
34 |
+ } |
|
35 |
+ } |
|
36 |
+ return daemon.nameIndex.Reserve(container.Name, container.ID) |
|
37 |
+} |
|
38 |
+ |
|
39 |
+func (daemon *Daemon) generateIDAndName(name string) (string, string, error) { |
|
40 |
+ var ( |
|
41 |
+ err error |
|
42 |
+ id = stringid.GenerateNonCryptoID() |
|
43 |
+ ) |
|
44 |
+ |
|
45 |
+ if name == "" { |
|
46 |
+ if name, err = daemon.generateNewName(id); err != nil { |
|
47 |
+ return "", "", err |
|
48 |
+ } |
|
49 |
+ return id, name, nil |
|
50 |
+ } |
|
51 |
+ |
|
52 |
+ if name, err = daemon.reserveName(id, name); err != nil { |
|
53 |
+ return "", "", err |
|
54 |
+ } |
|
55 |
+ |
|
56 |
+ return id, name, nil |
|
57 |
+} |
|
58 |
+ |
|
59 |
+func (daemon *Daemon) reserveName(id, name string) (string, error) { |
|
60 |
+ if !validContainerNamePattern.MatchString(name) { |
|
61 |
+ return "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars) |
|
62 |
+ } |
|
63 |
+ if name[0] != '/' { |
|
64 |
+ name = "/" + name |
|
65 |
+ } |
|
66 |
+ |
|
67 |
+ if err := daemon.nameIndex.Reserve(name, id); err != nil { |
|
68 |
+ if err == registrar.ErrNameReserved { |
|
69 |
+ id, err := daemon.nameIndex.Get(name) |
|
70 |
+ if err != nil { |
|
71 |
+ logrus.Errorf("got unexpected error while looking up reserved name: %v", err) |
|
72 |
+ return "", err |
|
73 |
+ } |
|
74 |
+ return "", fmt.Errorf("Conflict. The name %q is already in use by container %s. You have to remove (or rename) that container to be able to reuse that name.", name, id) |
|
75 |
+ } |
|
76 |
+ return "", fmt.Errorf("error reserving name: %s, error: %v", name, err) |
|
77 |
+ } |
|
78 |
+ return name, nil |
|
79 |
+} |
|
80 |
+ |
|
81 |
+func (daemon *Daemon) releaseName(name string) { |
|
82 |
+ daemon.nameIndex.Release(name) |
|
83 |
+} |
|
84 |
+ |
|
85 |
+func (daemon *Daemon) generateNewName(id string) (string, error) { |
|
86 |
+ var name string |
|
87 |
+ for i := 0; i < 6; i++ { |
|
88 |
+ name = namesgenerator.GetRandomName(i) |
|
89 |
+ if name[0] != '/' { |
|
90 |
+ name = "/" + name |
|
91 |
+ } |
|
92 |
+ |
|
93 |
+ if err := daemon.nameIndex.Reserve(name, id); err != nil { |
|
94 |
+ if err == registrar.ErrNameReserved { |
|
95 |
+ continue |
|
96 |
+ } |
|
97 |
+ return "", err |
|
98 |
+ } |
|
99 |
+ return name, nil |
|
100 |
+ } |
|
101 |
+ |
|
102 |
+ name = "/" + stringid.TruncateID(id) |
|
103 |
+ if err := daemon.nameIndex.Reserve(name, id); err != nil { |
|
104 |
+ return "", err |
|
105 |
+ } |
|
106 |
+ return name, nil |
|
107 |
+} |
... | ... |
@@ -8,6 +8,7 @@ import ( |
8 | 8 |
"golang.org/x/net/context" |
9 | 9 |
|
10 | 10 |
"github.com/docker/docker/api/types/backend" |
11 |
+ "github.com/docker/docker/container" |
|
11 | 12 |
"github.com/docker/docker/pkg/ioutils" |
12 | 13 |
"github.com/docker/engine-api/types" |
13 | 14 |
"github.com/docker/engine-api/types/versions" |
... | ... |
@@ -121,3 +122,11 @@ func (daemon *Daemon) ContainerStats(ctx context.Context, prefixOrName string, c |
121 | 121 |
} |
122 | 122 |
} |
123 | 123 |
} |
124 |
+ |
|
125 |
+func (daemon *Daemon) subscribeToContainerStats(c *container.Container) chan interface{} { |
|
126 |
+ return daemon.statsCollector.collect(c) |
|
127 |
+} |
|
128 |
+ |
|
129 |
+func (daemon *Daemon) unsubscribeToContainerStats(c *container.Container, ch chan interface{}) { |
|
130 |
+ daemon.statsCollector.unsubscribe(c, ch) |
|
131 |
+} |