github.com/nalind/docker@v1.5.0/daemon/daemon.go (about) 1 package daemon 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "os" 9 "path" 10 "path/filepath" 11 "regexp" 12 "runtime" 13 "strings" 14 "sync" 15 "time" 16 17 "github.com/docker/libcontainer/label" 18 19 log "github.com/Sirupsen/logrus" 20 "github.com/docker/docker/api" 21 "github.com/docker/docker/daemon/execdriver" 22 "github.com/docker/docker/daemon/execdriver/execdrivers" 23 "github.com/docker/docker/daemon/execdriver/lxc" 24 "github.com/docker/docker/daemon/graphdriver" 25 _ "github.com/docker/docker/daemon/graphdriver/vfs" 26 _ "github.com/docker/docker/daemon/networkdriver/bridge" 27 "github.com/docker/docker/daemon/networkdriver/portallocator" 28 "github.com/docker/docker/dockerversion" 29 "github.com/docker/docker/engine" 30 "github.com/docker/docker/graph" 31 "github.com/docker/docker/image" 32 "github.com/docker/docker/pkg/archive" 33 "github.com/docker/docker/pkg/broadcastwriter" 34 "github.com/docker/docker/pkg/graphdb" 35 "github.com/docker/docker/pkg/ioutils" 36 "github.com/docker/docker/pkg/namesgenerator" 37 "github.com/docker/docker/pkg/networkfs/resolvconf" 38 "github.com/docker/docker/pkg/parsers" 39 "github.com/docker/docker/pkg/parsers/kernel" 40 "github.com/docker/docker/pkg/sysinfo" 41 "github.com/docker/docker/pkg/truncindex" 42 "github.com/docker/docker/runconfig" 43 "github.com/docker/docker/trust" 44 "github.com/docker/docker/utils" 45 "github.com/docker/docker/volumes" 46 47 "github.com/go-fsnotify/fsnotify" 48 ) 49 50 var ( 51 validContainerNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]` 52 validContainerNamePattern = regexp.MustCompile(`^/?` + validContainerNameChars + `+$`) 53 ) 54 55 type contStore struct { 56 s map[string]*Container 57 sync.Mutex 58 } 59 60 func (c *contStore) Add(id string, cont *Container) { 61 c.Lock() 62 c.s[id] = cont 63 c.Unlock() 64 } 65 66 func (c *contStore) Get(id string) *Container { 67 c.Lock() 68 res := c.s[id] 69 c.Unlock() 70 return res 71 } 72 73 func (c *contStore) Delete(id string) { 74 c.Lock() 75 delete(c.s, id) 76 c.Unlock() 77 } 78 79 func (c *contStore) List() []*Container { 80 containers := new(History) 81 c.Lock() 82 for _, cont := range c.s { 83 containers.Add(cont) 84 } 85 c.Unlock() 86 containers.Sort() 87 return *containers 88 } 89 90 type Daemon struct { 91 ID string 92 repository string 93 sysInitPath string 94 containers *contStore 95 execCommands *execStore 96 graph *graph.Graph 97 repositories *graph.TagStore 98 idIndex *truncindex.TruncIndex 99 sysInfo *sysinfo.SysInfo 100 volumes *volumes.Repository 101 eng *engine.Engine 102 config *Config 103 containerGraph *graphdb.Database 104 driver graphdriver.Driver 105 execDriver execdriver.Driver 106 trustStore *trust.TrustStore 107 statsCollector *statsCollector 108 } 109 110 // Install installs daemon capabilities to eng. 111 func (daemon *Daemon) Install(eng *engine.Engine) error { 112 // FIXME: remove ImageDelete's dependency on Daemon, then move to graph/ 113 for name, method := range map[string]engine.Handler{ 114 "attach": daemon.ContainerAttach, 115 "commit": daemon.ContainerCommit, 116 "container_changes": daemon.ContainerChanges, 117 "container_copy": daemon.ContainerCopy, 118 "container_rename": daemon.ContainerRename, 119 "container_inspect": daemon.ContainerInspect, 120 "container_stats": daemon.ContainerStats, 121 "containers": daemon.Containers, 122 "create": daemon.ContainerCreate, 123 "rm": daemon.ContainerRm, 124 "export": daemon.ContainerExport, 125 "info": daemon.CmdInfo, 126 "kill": daemon.ContainerKill, 127 "logs": daemon.ContainerLogs, 128 "pause": daemon.ContainerPause, 129 "resize": daemon.ContainerResize, 130 "restart": daemon.ContainerRestart, 131 "start": daemon.ContainerStart, 132 "stop": daemon.ContainerStop, 133 "top": daemon.ContainerTop, 134 "unpause": daemon.ContainerUnpause, 135 "wait": daemon.ContainerWait, 136 "image_delete": daemon.ImageDelete, // FIXME: see above 137 "execCreate": daemon.ContainerExecCreate, 138 "execStart": daemon.ContainerExecStart, 139 "execResize": daemon.ContainerExecResize, 140 "execInspect": daemon.ContainerExecInspect, 141 } { 142 if err := eng.Register(name, method); err != nil { 143 return err 144 } 145 } 146 if err := daemon.Repositories().Install(eng); err != nil { 147 return err 148 } 149 if err := daemon.trustStore.Install(eng); err != nil { 150 return err 151 } 152 // FIXME: this hack is necessary for legacy integration tests to access 153 // the daemon object. 154 eng.Hack_SetGlobalVar("httpapi.daemon", daemon) 155 return nil 156 } 157 158 // Get looks for a container by the specified ID or name, and returns it. 159 // If the container is not found, or if an error occurs, nil is returned. 160 func (daemon *Daemon) Get(name string) *Container { 161 id, err := daemon.idIndex.Get(name) 162 if err == nil { 163 return daemon.containers.Get(id) 164 } 165 166 if c, _ := daemon.GetByName(name); c != nil { 167 return c 168 } 169 170 if err == truncindex.ErrDuplicateID { 171 log.Errorf("Short ID %s is ambiguous: please retry with more characters or use the full ID.\n", name) 172 } 173 return nil 174 } 175 176 // Exists returns a true if a container of the specified ID or name exists, 177 // false otherwise. 178 func (daemon *Daemon) Exists(id string) bool { 179 return daemon.Get(id) != nil 180 } 181 182 func (daemon *Daemon) containerRoot(id string) string { 183 return path.Join(daemon.repository, id) 184 } 185 186 // Load reads the contents of a container from disk 187 // This is typically done at startup. 188 func (daemon *Daemon) load(id string) (*Container, error) { 189 container := &Container{ 190 root: daemon.containerRoot(id), 191 State: NewState(), 192 execCommands: newExecStore(), 193 } 194 if err := container.FromDisk(); err != nil { 195 return nil, err 196 } 197 198 if container.ID != id { 199 return container, fmt.Errorf("Container %s is stored at %s", container.ID, id) 200 } 201 202 container.readHostConfig() 203 204 return container, nil 205 } 206 207 // Register makes a container object usable by the daemon as <container.ID> 208 // This is a wrapper for register 209 func (daemon *Daemon) Register(container *Container) error { 210 return daemon.register(container, true) 211 } 212 213 // register makes a container object usable by the daemon as <container.ID> 214 func (daemon *Daemon) register(container *Container, updateSuffixarray bool) error { 215 if container.daemon != nil || daemon.Exists(container.ID) { 216 return fmt.Errorf("Container is already loaded") 217 } 218 if err := validateID(container.ID); err != nil { 219 return err 220 } 221 if err := daemon.ensureName(container); err != nil { 222 return err 223 } 224 225 container.daemon = daemon 226 227 // Attach to stdout and stderr 228 container.stderr = broadcastwriter.New() 229 container.stdout = broadcastwriter.New() 230 // Attach to stdin 231 if container.Config.OpenStdin { 232 container.stdin, container.stdinPipe = io.Pipe() 233 } else { 234 container.stdinPipe = ioutils.NopWriteCloser(ioutil.Discard) // Silently drop stdin 235 } 236 // done 237 daemon.containers.Add(container.ID, container) 238 239 // don't update the Suffixarray if we're starting up 240 // we'll waste time if we update it for every container 241 daemon.idIndex.Add(container.ID) 242 243 container.registerVolumes() 244 245 // FIXME: if the container is supposed to be running but is not, auto restart it? 246 // if so, then we need to restart monitor and init a new lock 247 // If the container is supposed to be running, make sure of it 248 if container.IsRunning() { 249 log.Debugf("killing old running container %s", container.ID) 250 251 existingPid := container.Pid 252 container.SetStopped(&execdriver.ExitStatus{ExitCode: 0}) 253 254 // We only have to handle this for lxc because the other drivers will ensure that 255 // no processes are left when docker dies 256 if container.ExecDriver == "" || strings.Contains(container.ExecDriver, "lxc") { 257 lxc.KillLxc(container.ID, 9) 258 } else { 259 // use the current driver and ensure that the container is dead x.x 260 cmd := &execdriver.Command{ 261 ID: container.ID, 262 } 263 var err error 264 cmd.ProcessConfig.Process, err = os.FindProcess(existingPid) 265 if err != nil { 266 log.Debugf("cannot find existing process for %d", existingPid) 267 } 268 daemon.execDriver.Terminate(cmd) 269 } 270 271 if err := container.Unmount(); err != nil { 272 log.Debugf("unmount error %s", err) 273 } 274 if err := container.ToDisk(); err != nil { 275 log.Debugf("saving stopped state to disk %s", err) 276 } 277 278 info := daemon.execDriver.Info(container.ID) 279 if !info.IsRunning() { 280 log.Debugf("Container %s was supposed to be running but is not.", container.ID) 281 282 log.Debugf("Marking as stopped") 283 284 container.SetStopped(&execdriver.ExitStatus{ExitCode: -127}) 285 if err := container.ToDisk(); err != nil { 286 return err 287 } 288 } 289 } 290 return nil 291 } 292 293 func (daemon *Daemon) ensureName(container *Container) error { 294 if container.Name == "" { 295 name, err := daemon.generateNewName(container.ID) 296 if err != nil { 297 return err 298 } 299 container.Name = name 300 301 if err := container.ToDisk(); err != nil { 302 log.Debugf("Error saving container name %s", err) 303 } 304 } 305 return nil 306 } 307 308 func (daemon *Daemon) LogToDisk(src *broadcastwriter.BroadcastWriter, dst, stream string) error { 309 log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600) 310 if err != nil { 311 return err 312 } 313 src.AddWriter(log, stream) 314 return nil 315 } 316 317 func (daemon *Daemon) restore() error { 318 var ( 319 debug = (os.Getenv("DEBUG") != "" || os.Getenv("TEST") != "") 320 containers = make(map[string]*Container) 321 currentDriver = daemon.driver.String() 322 ) 323 324 if !debug { 325 log.Infof("Loading containers: start.") 326 } 327 dir, err := ioutil.ReadDir(daemon.repository) 328 if err != nil { 329 return err 330 } 331 332 for _, v := range dir { 333 id := v.Name() 334 container, err := daemon.load(id) 335 if !debug { 336 fmt.Print(".") 337 } 338 if err != nil { 339 log.Errorf("Failed to load container %v: %v", id, err) 340 continue 341 } 342 343 // Ignore the container if it does not support the current driver being used by the graph 344 if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver { 345 log.Debugf("Loaded container %v", container.ID) 346 347 containers[container.ID] = container 348 } else { 349 log.Debugf("Cannot load container %s because it was created with another graph driver.", container.ID) 350 } 351 } 352 353 registeredContainers := []*Container{} 354 355 if entities := daemon.containerGraph.List("/", -1); entities != nil { 356 for _, p := range entities.Paths() { 357 if !debug { 358 fmt.Print(".") 359 } 360 361 e := entities[p] 362 363 if container, ok := containers[e.ID()]; ok { 364 if err := daemon.register(container, false); err != nil { 365 log.Debugf("Failed to register container %s: %s", container.ID, err) 366 } 367 368 registeredContainers = append(registeredContainers, container) 369 370 // delete from the map so that a new name is not automatically generated 371 delete(containers, e.ID()) 372 } 373 } 374 } 375 376 // Any containers that are left over do not exist in the graph 377 for _, container := range containers { 378 // Try to set the default name for a container if it exists prior to links 379 container.Name, err = daemon.generateNewName(container.ID) 380 if err != nil { 381 log.Debugf("Setting default id - %s", err) 382 } 383 384 if err := daemon.register(container, false); err != nil { 385 log.Debugf("Failed to register container %s: %s", container.ID, err) 386 } 387 388 registeredContainers = append(registeredContainers, container) 389 } 390 391 // check the restart policy on the containers and restart any container with 392 // the restart policy of "always" 393 if daemon.config.AutoRestart { 394 log.Debugf("Restarting containers...") 395 396 for _, container := range registeredContainers { 397 if container.hostConfig.RestartPolicy.Name == "always" || 398 (container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0) { 399 log.Debugf("Starting container %s", container.ID) 400 401 if err := container.Start(); err != nil { 402 log.Debugf("Failed to start container %s: %s", container.ID, err) 403 } 404 } 405 } 406 } 407 408 if !debug { 409 fmt.Println() 410 log.Infof("Loading containers: done.") 411 } 412 413 return nil 414 } 415 416 // set up the watch on the host's /etc/resolv.conf so that we can update container's 417 // live resolv.conf when the network changes on the host 418 func (daemon *Daemon) setupResolvconfWatcher() error { 419 420 watcher, err := fsnotify.NewWatcher() 421 if err != nil { 422 return err 423 } 424 425 //this goroutine listens for the events on the watch we add 426 //on the resolv.conf file on the host 427 go func() { 428 for { 429 select { 430 case event := <-watcher.Events: 431 if event.Op&fsnotify.Write == fsnotify.Write { 432 // verify a real change happened before we go further--a file write may have happened 433 // without an actual change to the file 434 updatedResolvConf, newResolvConfHash, err := resolvconf.GetIfChanged() 435 if err != nil { 436 log.Debugf("Error retrieving updated host resolv.conf: %v", err) 437 } else if updatedResolvConf != nil { 438 // because the new host resolv.conf might have localhost nameservers.. 439 updatedResolvConf, modified := resolvconf.FilterResolvDns(updatedResolvConf, daemon.config.EnableIPv6) 440 if modified { 441 // changes have occurred during localhost cleanup: generate an updated hash 442 newHash, err := utils.HashData(bytes.NewReader(updatedResolvConf)) 443 if err != nil { 444 log.Debugf("Error generating hash of new resolv.conf: %v", err) 445 } else { 446 newResolvConfHash = newHash 447 } 448 } 449 log.Debugf("host network resolv.conf changed--walking container list for updates") 450 contList := daemon.containers.List() 451 for _, container := range contList { 452 if err := container.updateResolvConf(updatedResolvConf, newResolvConfHash); err != nil { 453 log.Debugf("Error on resolv.conf update check for container ID: %s: %v", container.ID, err) 454 } 455 } 456 } 457 } 458 case err := <-watcher.Errors: 459 log.Debugf("host resolv.conf notify error: %v", err) 460 } 461 } 462 }() 463 464 if err := watcher.Add("/etc/resolv.conf"); err != nil { 465 return err 466 } 467 return nil 468 } 469 470 func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool { 471 if config != nil { 472 if config.PortSpecs != nil { 473 for _, p := range config.PortSpecs { 474 if strings.Contains(p, ":") { 475 return true 476 } 477 } 478 } 479 } 480 return false 481 } 482 483 func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image.Image) ([]string, error) { 484 warnings := []string{} 485 if (img != nil && daemon.checkDeprecatedExpose(img.Config)) || daemon.checkDeprecatedExpose(config) { 486 warnings = append(warnings, "The mapping to public ports on your host via Dockerfile EXPOSE (host:port:port) has been deprecated. Use -p to publish the ports.") 487 } 488 if img != nil && img.Config != nil { 489 if err := runconfig.Merge(config, img.Config); err != nil { 490 return nil, err 491 } 492 } 493 if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 { 494 return nil, fmt.Errorf("No command specified") 495 } 496 return warnings, nil 497 } 498 499 func (daemon *Daemon) generateIdAndName(name string) (string, string, error) { 500 var ( 501 err error 502 id = utils.GenerateRandomID() 503 ) 504 505 if name == "" { 506 if name, err = daemon.generateNewName(id); err != nil { 507 return "", "", err 508 } 509 return id, name, nil 510 } 511 512 if name, err = daemon.reserveName(id, name); err != nil { 513 return "", "", err 514 } 515 516 return id, name, nil 517 } 518 519 func (daemon *Daemon) reserveName(id, name string) (string, error) { 520 if !validContainerNamePattern.MatchString(name) { 521 return "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars) 522 } 523 524 if name[0] != '/' { 525 name = "/" + name 526 } 527 528 if _, err := daemon.containerGraph.Set(name, id); err != nil { 529 if !graphdb.IsNonUniqueNameError(err) { 530 return "", err 531 } 532 533 conflictingContainer, err := daemon.GetByName(name) 534 if err != nil { 535 if strings.Contains(err.Error(), "Could not find entity") { 536 return "", err 537 } 538 539 // Remove name and continue starting the container 540 if err := daemon.containerGraph.Delete(name); err != nil { 541 return "", err 542 } 543 } else { 544 nameAsKnownByUser := strings.TrimPrefix(name, "/") 545 return "", fmt.Errorf( 546 "Conflict. The name %q is already in use by container %s. You have to delete (or rename) that container to be able to reuse that name.", nameAsKnownByUser, 547 utils.TruncateID(conflictingContainer.ID)) 548 } 549 } 550 return name, nil 551 } 552 553 func (daemon *Daemon) generateNewName(id string) (string, error) { 554 var name string 555 for i := 0; i < 6; i++ { 556 name = namesgenerator.GetRandomName(i) 557 if name[0] != '/' { 558 name = "/" + name 559 } 560 561 if _, err := daemon.containerGraph.Set(name, id); err != nil { 562 if !graphdb.IsNonUniqueNameError(err) { 563 return "", err 564 } 565 continue 566 } 567 return name, nil 568 } 569 570 name = "/" + utils.TruncateID(id) 571 if _, err := daemon.containerGraph.Set(name, id); err != nil { 572 return "", err 573 } 574 return name, nil 575 } 576 577 func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) { 578 // Generate default hostname 579 // FIXME: the lxc template no longer needs to set a default hostname 580 if config.Hostname == "" { 581 config.Hostname = id[:12] 582 } 583 } 584 585 func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint, configCmd []string) (string, []string) { 586 var ( 587 entrypoint string 588 args []string 589 ) 590 if len(configEntrypoint) != 0 { 591 entrypoint = configEntrypoint[0] 592 args = append(configEntrypoint[1:], configCmd...) 593 } else { 594 entrypoint = configCmd[0] 595 args = configCmd[1:] 596 } 597 return entrypoint, args 598 } 599 600 func parseSecurityOpt(container *Container, config *runconfig.HostConfig) error { 601 var ( 602 labelOpts []string 603 err error 604 ) 605 606 for _, opt := range config.SecurityOpt { 607 con := strings.SplitN(opt, ":", 2) 608 if len(con) == 1 { 609 return fmt.Errorf("Invalid --security-opt: %q", opt) 610 } 611 switch con[0] { 612 case "label": 613 labelOpts = append(labelOpts, con[1]) 614 case "apparmor": 615 container.AppArmorProfile = con[1] 616 default: 617 return fmt.Errorf("Invalid --security-opt: %q", opt) 618 } 619 } 620 621 container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts) 622 return err 623 } 624 625 func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID string) (*Container, error) { 626 var ( 627 id string 628 err error 629 ) 630 id, name, err = daemon.generateIdAndName(name) 631 if err != nil { 632 return nil, err 633 } 634 635 daemon.generateHostname(id, config) 636 entrypoint, args := daemon.getEntrypointAndArgs(config.Entrypoint, config.Cmd) 637 638 container := &Container{ 639 // FIXME: we should generate the ID here instead of receiving it as an argument 640 ID: id, 641 Created: time.Now().UTC(), 642 Path: entrypoint, 643 Args: args, //FIXME: de-duplicate from config 644 Config: config, 645 hostConfig: &runconfig.HostConfig{}, 646 ImageID: imgID, 647 NetworkSettings: &NetworkSettings{}, 648 Name: name, 649 Driver: daemon.driver.String(), 650 ExecDriver: daemon.execDriver.Name(), 651 State: NewState(), 652 execCommands: newExecStore(), 653 } 654 container.root = daemon.containerRoot(container.ID) 655 return container, err 656 } 657 658 func (daemon *Daemon) createRootfs(container *Container) error { 659 // Step 1: create the container directory. 660 // This doubles as a barrier to avoid race conditions. 661 if err := os.Mkdir(container.root, 0700); err != nil { 662 return err 663 } 664 initID := fmt.Sprintf("%s-init", container.ID) 665 if err := daemon.driver.Create(initID, container.ImageID); err != nil { 666 return err 667 } 668 initPath, err := daemon.driver.Get(initID, "") 669 if err != nil { 670 return err 671 } 672 defer daemon.driver.Put(initID) 673 674 if err := graph.SetupInitLayer(initPath); err != nil { 675 return err 676 } 677 678 if err := daemon.driver.Create(container.ID, initID); err != nil { 679 return err 680 } 681 return nil 682 } 683 684 func GetFullContainerName(name string) (string, error) { 685 if name == "" { 686 return "", fmt.Errorf("Container name cannot be empty") 687 } 688 if name[0] != '/' { 689 name = "/" + name 690 } 691 return name, nil 692 } 693 694 func (daemon *Daemon) GetByName(name string) (*Container, error) { 695 fullName, err := GetFullContainerName(name) 696 if err != nil { 697 return nil, err 698 } 699 entity := daemon.containerGraph.Get(fullName) 700 if entity == nil { 701 return nil, fmt.Errorf("Could not find entity for %s", name) 702 } 703 e := daemon.containers.Get(entity.ID()) 704 if e == nil { 705 return nil, fmt.Errorf("Could not find container for entity id %s", entity.ID()) 706 } 707 return e, nil 708 } 709 710 func (daemon *Daemon) Children(name string) (map[string]*Container, error) { 711 name, err := GetFullContainerName(name) 712 if err != nil { 713 return nil, err 714 } 715 children := make(map[string]*Container) 716 717 err = daemon.containerGraph.Walk(name, func(p string, e *graphdb.Entity) error { 718 c := daemon.Get(e.ID()) 719 if c == nil { 720 return fmt.Errorf("Could not get container for name %s and id %s", e.ID(), p) 721 } 722 children[p] = c 723 return nil 724 }, 0) 725 726 if err != nil { 727 return nil, err 728 } 729 return children, nil 730 } 731 732 func (daemon *Daemon) Parents(name string) ([]string, error) { 733 name, err := GetFullContainerName(name) 734 if err != nil { 735 return nil, err 736 } 737 738 return daemon.containerGraph.Parents(name) 739 } 740 741 func (daemon *Daemon) RegisterLink(parent, child *Container, alias string) error { 742 fullName := path.Join(parent.Name, alias) 743 if !daemon.containerGraph.Exists(fullName) { 744 _, err := daemon.containerGraph.Set(fullName, child.ID) 745 return err 746 } 747 return nil 748 } 749 750 func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.HostConfig) error { 751 if hostConfig != nil && hostConfig.Links != nil { 752 for _, l := range hostConfig.Links { 753 parts, err := parsers.PartParser("name:alias", l) 754 if err != nil { 755 return err 756 } 757 child := daemon.Get(parts["name"]) 758 if child == nil { 759 return fmt.Errorf("Could not get container for %s", parts["name"]) 760 } 761 if child.hostConfig.NetworkMode.IsHost() { 762 return runconfig.ErrConflictHostNetworkAndLinks 763 } 764 if err := daemon.RegisterLink(container, child, parts["alias"]); err != nil { 765 return err 766 } 767 } 768 769 // After we load all the links into the daemon 770 // set them to nil on the hostconfig 771 hostConfig.Links = nil 772 if err := container.WriteHostConfig(); err != nil { 773 return err 774 } 775 } 776 return nil 777 } 778 779 // FIXME: harmonize with NewGraph() 780 func NewDaemon(config *Config, eng *engine.Engine) (*Daemon, error) { 781 daemon, err := NewDaemonFromDirectory(config, eng) 782 if err != nil { 783 return nil, err 784 } 785 return daemon, nil 786 } 787 788 func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error) { 789 if config.Mtu == 0 { 790 config.Mtu = getDefaultNetworkMtu() 791 } 792 // Check for mutually incompatible config options 793 if config.BridgeIface != "" && config.BridgeIP != "" { 794 return nil, fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.") 795 } 796 if !config.EnableIptables && !config.InterContainerCommunication { 797 return nil, fmt.Errorf("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.") 798 } 799 if !config.EnableIptables && config.EnableIpMasq { 800 config.EnableIpMasq = false 801 } 802 config.DisableNetwork = config.BridgeIface == disableNetworkBridge 803 804 // Claim the pidfile first, to avoid any and all unexpected race conditions. 805 // Some of the init doesn't need a pidfile lock - but let's not try to be smart. 806 if config.Pidfile != "" { 807 if err := utils.CreatePidFile(config.Pidfile); err != nil { 808 return nil, err 809 } 810 eng.OnShutdown(func() { 811 // Always release the pidfile last, just in case 812 utils.RemovePidFile(config.Pidfile) 813 }) 814 } 815 816 // Check that the system is supported and we have sufficient privileges 817 if runtime.GOOS != "linux" { 818 return nil, fmt.Errorf("The Docker daemon is only supported on linux") 819 } 820 if os.Geteuid() != 0 { 821 return nil, fmt.Errorf("The Docker daemon needs to be run as root") 822 } 823 if err := checkKernel(); err != nil { 824 return nil, err 825 } 826 827 // set up the TempDir to use a canonical path 828 tmp, err := utils.TempDir(config.Root) 829 if err != nil { 830 return nil, fmt.Errorf("Unable to get the TempDir under %s: %s", config.Root, err) 831 } 832 realTmp, err := utils.ReadSymlinkedDirectory(tmp) 833 if err != nil { 834 return nil, fmt.Errorf("Unable to get the full path to the TempDir (%s): %s", tmp, err) 835 } 836 os.Setenv("TMPDIR", realTmp) 837 if !config.EnableSelinuxSupport { 838 selinuxSetDisabled() 839 } 840 841 // get the canonical path to the Docker root directory 842 var realRoot string 843 if _, err := os.Stat(config.Root); err != nil && os.IsNotExist(err) { 844 realRoot = config.Root 845 } else { 846 realRoot, err = utils.ReadSymlinkedDirectory(config.Root) 847 if err != nil { 848 return nil, fmt.Errorf("Unable to get the full path to root (%s): %s", config.Root, err) 849 } 850 } 851 config.Root = realRoot 852 // Create the root directory if it doesn't exists 853 if err := os.MkdirAll(config.Root, 0700); err != nil && !os.IsExist(err) { 854 return nil, err 855 } 856 857 // Set the default driver 858 graphdriver.DefaultDriver = config.GraphDriver 859 860 // Load storage driver 861 driver, err := graphdriver.New(config.Root, config.GraphOptions) 862 if err != nil { 863 return nil, err 864 } 865 log.Debugf("Using graph driver %s", driver) 866 867 // As Docker on btrfs and SELinux are incompatible at present, error on both being enabled 868 if selinuxEnabled() && config.EnableSelinuxSupport && driver.String() == "btrfs" { 869 return nil, fmt.Errorf("SELinux is not supported with the BTRFS graph driver!") 870 } 871 872 daemonRepo := path.Join(config.Root, "containers") 873 874 if err := os.MkdirAll(daemonRepo, 0700); err != nil && !os.IsExist(err) { 875 return nil, err 876 } 877 878 // Migrate the container if it is aufs and aufs is enabled 879 if err = migrateIfAufs(driver, config.Root); err != nil { 880 return nil, err 881 } 882 883 log.Debugf("Creating images graph") 884 g, err := graph.NewGraph(path.Join(config.Root, "graph"), driver) 885 if err != nil { 886 return nil, err 887 } 888 889 volumesDriver, err := graphdriver.GetDriver("vfs", config.Root, config.GraphOptions) 890 if err != nil { 891 return nil, err 892 } 893 894 volumes, err := volumes.NewRepository(filepath.Join(config.Root, "volumes"), volumesDriver) 895 if err != nil { 896 return nil, err 897 } 898 899 trustKey, err := api.LoadOrCreateTrustKey(config.TrustKeyPath) 900 if err != nil { 901 return nil, err 902 } 903 904 log.Debugf("Creating repository list") 905 repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), g, trustKey) 906 if err != nil { 907 return nil, fmt.Errorf("Couldn't create Tag store: %s", err) 908 } 909 910 trustDir := path.Join(config.Root, "trust") 911 if err := os.MkdirAll(trustDir, 0700); err != nil && !os.IsExist(err) { 912 return nil, err 913 } 914 t, err := trust.NewTrustStore(trustDir) 915 if err != nil { 916 return nil, fmt.Errorf("could not create trust store: %s", err) 917 } 918 919 if !config.DisableNetwork { 920 job := eng.Job("init_networkdriver") 921 922 job.SetenvBool("EnableIptables", config.EnableIptables) 923 job.SetenvBool("InterContainerCommunication", config.InterContainerCommunication) 924 job.SetenvBool("EnableIpForward", config.EnableIpForward) 925 job.SetenvBool("EnableIpMasq", config.EnableIpMasq) 926 job.SetenvBool("EnableIPv6", config.EnableIPv6) 927 job.Setenv("BridgeIface", config.BridgeIface) 928 job.Setenv("BridgeIP", config.BridgeIP) 929 job.Setenv("FixedCIDR", config.FixedCIDR) 930 job.Setenv("FixedCIDRv6", config.FixedCIDRv6) 931 job.Setenv("DefaultBindingIP", config.DefaultIp.String()) 932 933 if err := job.Run(); err != nil { 934 return nil, err 935 } 936 } 937 938 graphdbPath := path.Join(config.Root, "linkgraph.db") 939 graph, err := graphdb.NewSqliteConn(graphdbPath) 940 if err != nil { 941 return nil, err 942 } 943 944 localCopy := path.Join(config.Root, "init", fmt.Sprintf("dockerinit-%s", dockerversion.VERSION)) 945 sysInitPath := utils.DockerInitPath(localCopy) 946 if sysInitPath == "" { 947 return nil, fmt.Errorf("Could not locate dockerinit: This usually means docker was built incorrectly. See http://docs.docker.com/contributing/devenvironment for official build instructions.") 948 } 949 950 if sysInitPath != localCopy { 951 // When we find a suitable dockerinit binary (even if it's our local binary), we copy it into config.Root at localCopy for future use (so that the original can go away without that being a problem, for example during a package upgrade). 952 if err := os.Mkdir(path.Dir(localCopy), 0700); err != nil && !os.IsExist(err) { 953 return nil, err 954 } 955 if _, err := utils.CopyFile(sysInitPath, localCopy); err != nil { 956 return nil, err 957 } 958 if err := os.Chmod(localCopy, 0700); err != nil { 959 return nil, err 960 } 961 sysInitPath = localCopy 962 } 963 964 sysInfo := sysinfo.New(false) 965 ed, err := execdrivers.NewDriver(config.ExecDriver, config.Root, sysInitPath, sysInfo) 966 if err != nil { 967 return nil, err 968 } 969 970 daemon := &Daemon{ 971 ID: trustKey.PublicKey().KeyID(), 972 repository: daemonRepo, 973 containers: &contStore{s: make(map[string]*Container)}, 974 execCommands: newExecStore(), 975 graph: g, 976 repositories: repositories, 977 idIndex: truncindex.NewTruncIndex([]string{}), 978 sysInfo: sysInfo, 979 volumes: volumes, 980 config: config, 981 containerGraph: graph, 982 driver: driver, 983 sysInitPath: sysInitPath, 984 execDriver: ed, 985 eng: eng, 986 trustStore: t, 987 statsCollector: newStatsCollector(1 * time.Second), 988 } 989 if err := daemon.restore(); err != nil { 990 return nil, err 991 } 992 993 // set up filesystem watch on resolv.conf for network changes 994 if err := daemon.setupResolvconfWatcher(); err != nil { 995 return nil, err 996 } 997 998 // Setup shutdown handlers 999 // FIXME: can these shutdown handlers be registered closer to their source? 1000 eng.OnShutdown(func() { 1001 // FIXME: if these cleanup steps can be called concurrently, register 1002 // them as separate handlers to speed up total shutdown time 1003 if err := daemon.shutdown(); err != nil { 1004 log.Errorf("daemon.shutdown(): %s", err) 1005 } 1006 if err := portallocator.ReleaseAll(); err != nil { 1007 log.Errorf("portallocator.ReleaseAll(): %s", err) 1008 } 1009 if err := daemon.driver.Cleanup(); err != nil { 1010 log.Errorf("daemon.driver.Cleanup(): %s", err.Error()) 1011 } 1012 if err := daemon.containerGraph.Close(); err != nil { 1013 log.Errorf("daemon.containerGraph.Close(): %s", err.Error()) 1014 } 1015 }) 1016 1017 return daemon, nil 1018 } 1019 1020 func (daemon *Daemon) shutdown() error { 1021 group := sync.WaitGroup{} 1022 log.Debugf("starting clean shutdown of all containers...") 1023 for _, container := range daemon.List() { 1024 c := container 1025 if c.IsRunning() { 1026 log.Debugf("stopping %s", c.ID) 1027 group.Add(1) 1028 1029 go func() { 1030 defer group.Done() 1031 if err := c.KillSig(15); err != nil { 1032 log.Debugf("kill 15 error for %s - %s", c.ID, err) 1033 } 1034 c.WaitStop(-1 * time.Second) 1035 log.Debugf("container stopped %s", c.ID) 1036 }() 1037 } 1038 } 1039 group.Wait() 1040 1041 return nil 1042 } 1043 1044 func (daemon *Daemon) Mount(container *Container) error { 1045 dir, err := daemon.driver.Get(container.ID, container.GetMountLabel()) 1046 if err != nil { 1047 return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, daemon.driver, err) 1048 } 1049 if container.basefs == "" { 1050 container.basefs = dir 1051 } else if container.basefs != dir { 1052 daemon.driver.Put(container.ID) 1053 return fmt.Errorf("Error: driver %s is returning inconsistent paths for container %s ('%s' then '%s')", 1054 daemon.driver, container.ID, container.basefs, dir) 1055 } 1056 return nil 1057 } 1058 1059 func (daemon *Daemon) Unmount(container *Container) error { 1060 daemon.driver.Put(container.ID) 1061 return nil 1062 } 1063 1064 func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) { 1065 initID := fmt.Sprintf("%s-init", container.ID) 1066 return daemon.driver.Changes(container.ID, initID) 1067 } 1068 1069 func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) { 1070 initID := fmt.Sprintf("%s-init", container.ID) 1071 return daemon.driver.Diff(container.ID, initID) 1072 } 1073 1074 func (daemon *Daemon) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) { 1075 return daemon.execDriver.Run(c.command, pipes, startCallback) 1076 } 1077 1078 func (daemon *Daemon) Pause(c *Container) error { 1079 if err := daemon.execDriver.Pause(c.command); err != nil { 1080 return err 1081 } 1082 c.SetPaused() 1083 return nil 1084 } 1085 1086 func (daemon *Daemon) Unpause(c *Container) error { 1087 if err := daemon.execDriver.Unpause(c.command); err != nil { 1088 return err 1089 } 1090 c.SetUnpaused() 1091 return nil 1092 } 1093 1094 func (daemon *Daemon) Kill(c *Container, sig int) error { 1095 return daemon.execDriver.Kill(c.command, sig) 1096 } 1097 1098 func (daemon *Daemon) Stats(c *Container) (*execdriver.ResourceStats, error) { 1099 return daemon.execDriver.Stats(c.ID) 1100 } 1101 1102 func (daemon *Daemon) SubscribeToContainerStats(name string) (chan interface{}, error) { 1103 c := daemon.Get(name) 1104 if c == nil { 1105 return nil, fmt.Errorf("no such container") 1106 } 1107 ch := daemon.statsCollector.collect(c) 1108 return ch, nil 1109 } 1110 1111 func (daemon *Daemon) UnsubscribeToContainerStats(name string, ch chan interface{}) error { 1112 c := daemon.Get(name) 1113 if c == nil { 1114 return fmt.Errorf("no such container") 1115 } 1116 daemon.statsCollector.unsubscribe(c, ch) 1117 return nil 1118 } 1119 1120 // Nuke kills all containers then removes all content 1121 // from the content root, including images, volumes and 1122 // container filesystems. 1123 // Again: this will remove your entire docker daemon! 1124 // FIXME: this is deprecated, and only used in legacy 1125 // tests. Please remove. 1126 func (daemon *Daemon) Nuke() error { 1127 var wg sync.WaitGroup 1128 for _, container := range daemon.List() { 1129 wg.Add(1) 1130 go func(c *Container) { 1131 c.Kill() 1132 wg.Done() 1133 }(container) 1134 } 1135 wg.Wait() 1136 1137 return os.RemoveAll(daemon.config.Root) 1138 } 1139 1140 // FIXME: this is a convenience function for integration tests 1141 // which need direct access to daemon.graph. 1142 // Once the tests switch to using engine and jobs, this method 1143 // can go away. 1144 func (daemon *Daemon) Graph() *graph.Graph { 1145 return daemon.graph 1146 } 1147 1148 func (daemon *Daemon) Repositories() *graph.TagStore { 1149 return daemon.repositories 1150 } 1151 1152 func (daemon *Daemon) Config() *Config { 1153 return daemon.config 1154 } 1155 1156 func (daemon *Daemon) SystemConfig() *sysinfo.SysInfo { 1157 return daemon.sysInfo 1158 } 1159 1160 func (daemon *Daemon) SystemInitPath() string { 1161 return daemon.sysInitPath 1162 } 1163 1164 func (daemon *Daemon) GraphDriver() graphdriver.Driver { 1165 return daemon.driver 1166 } 1167 1168 func (daemon *Daemon) ExecutionDriver() execdriver.Driver { 1169 return daemon.execDriver 1170 } 1171 1172 func (daemon *Daemon) ContainerGraph() *graphdb.Database { 1173 return daemon.containerGraph 1174 } 1175 1176 func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*image.Image, error) { 1177 // Retrieve all images 1178 images, err := daemon.Graph().Map() 1179 if err != nil { 1180 return nil, err 1181 } 1182 1183 // Store the tree in a map of map (map[parentId][childId]) 1184 imageMap := make(map[string]map[string]struct{}) 1185 for _, img := range images { 1186 if _, exists := imageMap[img.Parent]; !exists { 1187 imageMap[img.Parent] = make(map[string]struct{}) 1188 } 1189 imageMap[img.Parent][img.ID] = struct{}{} 1190 } 1191 1192 // Loop on the children of the given image and check the config 1193 var match *image.Image 1194 for elem := range imageMap[imgID] { 1195 img, ok := images[elem] 1196 if !ok { 1197 return nil, fmt.Errorf("unable to find image %q", elem) 1198 } 1199 if runconfig.Compare(&img.ContainerConfig, config) { 1200 if match == nil || match.Created.Before(img.Created) { 1201 match = img 1202 } 1203 } 1204 } 1205 return match, nil 1206 } 1207 1208 func checkKernel() error { 1209 // Check for unsupported kernel versions 1210 // FIXME: it would be cleaner to not test for specific versions, but rather 1211 // test for specific functionalities. 1212 // Unfortunately we can't test for the feature "does not cause a kernel panic" 1213 // without actually causing a kernel panic, so we need this workaround until 1214 // the circumstances of pre-3.8 crashes are clearer. 1215 // For details see http://github.com/docker/docker/issues/407 1216 if k, err := kernel.GetKernelVersion(); err != nil { 1217 log.Infof("WARNING: %s", err) 1218 } else { 1219 if kernel.CompareKernelVersion(k, &kernel.KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 { 1220 if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" { 1221 log.Infof("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String()) 1222 } 1223 } 1224 } 1225 return nil 1226 }