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