Signed-off-by: Vincent Demeester <vincent@sbr.pm>
| 16 | 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 |
+} |