daemon/daemon.go
359b7df5
 package daemon
a27b4b8c
 
 import (
 	"fmt"
46e05ed2
 	"io"
 	"io/ioutil"
 	"log"
 	"os"
 	"path"
 	"regexp"
 	"strings"
 	"sync"
 	"time"
 
81945563
 	"github.com/docker/libcontainer/label"
 	"github.com/docker/libcontainer/selinux"
9ae4bcaa
 	"github.com/dotcloud/docker/archive"
359b7df5
 	"github.com/dotcloud/docker/daemon/execdriver"
 	"github.com/dotcloud/docker/daemon/execdriver/execdrivers"
 	"github.com/dotcloud/docker/daemon/execdriver/lxc"
 	"github.com/dotcloud/docker/daemon/graphdriver"
 	_ "github.com/dotcloud/docker/daemon/graphdriver/vfs"
 	_ "github.com/dotcloud/docker/daemon/networkdriver/bridge"
 	"github.com/dotcloud/docker/daemon/networkdriver/portallocator"
12bd8318
 	"github.com/dotcloud/docker/daemonconfig"
da04f49b
 	"github.com/dotcloud/docker/dockerversion"
c712e74b
 	"github.com/dotcloud/docker/engine"
2bddcd68
 	"github.com/dotcloud/docker/graph"
 	"github.com/dotcloud/docker/image"
 	"github.com/dotcloud/docker/pkg/graphdb"
6ec86cb6
 	"github.com/dotcloud/docker/pkg/namesgenerator"
3744452e
 	"github.com/dotcloud/docker/pkg/networkfs/resolvconf"
2bddcd68
 	"github.com/dotcloud/docker/pkg/sysinfo"
 	"github.com/dotcloud/docker/runconfig"
2e69e172
 	"github.com/dotcloud/docker/utils"
a27b4b8c
 )
 
6d34c50e
 // Set the max depth to the aufs default that most
 // kernels are compiled with
 // For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk
 const MaxImageDepth = 127
af753cba
 
f63cdf02
 var (
36c3614f
 	DefaultDns                = []string{"8.8.8.8", "8.8.4.4"}
3ec39ad0
 	validContainerNameChars   = `[a-zA-Z0-9_.-]`
 	validContainerNamePattern = regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
f63cdf02
 )
24e02043
 
af17b01a
 type contStore struct {
 	s map[string]*Container
 	sync.Mutex
 }
 
 func (c *contStore) Add(id string, cont *Container) {
 	c.Lock()
 	c.s[id] = cont
 	c.Unlock()
 }
 
 func (c *contStore) Get(id string) *Container {
 	c.Lock()
 	res := c.s[id]
 	c.Unlock()
 	return res
 }
 
 func (c *contStore) Delete(id string) {
 	c.Lock()
 	delete(c.s, id)
 	c.Unlock()
 }
 
 func (c *contStore) List() []*Container {
 	containers := new(History)
0b3fe554
 	c.Lock()
af17b01a
 	for _, cont := range c.s {
 		containers.Add(cont)
 	}
0b3fe554
 	c.Unlock()
af17b01a
 	containers.Sort()
 	return *containers
 }
 
359b7df5
 type Daemon struct {
bd2f5129
 	repository     string
110c4f20
 	sysInitPath    string
af17b01a
 	containers     *contStore
01b6b2be
 	graph          *graph.Graph
 	repositories   *graph.TagStore
2e69e172
 	idIndex        *utils.TruncIndex
9e9f4b92
 	sysInfo        *sysinfo.SysInfo
01b6b2be
 	volumes        *graph.Graph
36c3614f
 	srv            Server
49b98130
 	eng            *engine.Engine
12bd8318
 	config         *daemonconfig.Config
cbd1281e
 	containerGraph *graphdb.Database
f2bab155
 	driver         graphdriver.Driver
f2680e5a
 	execDriver     execdriver.Driver
7c57a4cf
 }
 
603e00a3
 // Install installs daemon capabilities to eng.
 func (daemon *Daemon) Install(eng *engine.Engine) error {
 	return eng.Register("container_inspect", daemon.ContainerInspect)
 }
 
359b7df5
 // List returns an array of all containers registered in the daemon.
 func (daemon *Daemon) List() []*Container {
af17b01a
 	return daemon.containers.List()
a27b4b8c
 }
 
6a9f4ecf
 // Get looks for a container by the specified ID or name, and returns it.
 // If the container is not found, or if an error occurs, nil is returned.
359b7df5
 func (daemon *Daemon) Get(name string) *Container {
 	if c, _ := daemon.GetByName(name); c != nil {
1cbdaeba
 		return c
 	}
 
359b7df5
 	id, err := daemon.idIndex.Get(name)
0b9a3c86
 	if err != nil {
 		return nil
 	}
1cbdaeba
 
af17b01a
 	return daemon.containers.Get(id)
a27b4b8c
 }
 
6a9f4ecf
 // Exists returns a true if a container of the specified ID or name exists,
 // false otherwise.
359b7df5
 func (daemon *Daemon) Exists(id string) bool {
 	return daemon.Get(id) != nil
a27b4b8c
 }
 
359b7df5
 func (daemon *Daemon) containerRoot(id string) string {
 	return path.Join(daemon.repository, id)
7c57a4cf
 }
 
1cbdaeba
 // Load reads the contents of a container from disk
6a9f4ecf
 // This is typically done at startup.
359b7df5
 func (daemon *Daemon) load(id string) (*Container, error) {
 	container := &Container{root: daemon.containerRoot(id)}
7c57a4cf
 	if err := container.FromDisk(); err != nil {
 		return nil, err
 	}
fd224ee5
 	if container.ID != id {
 		return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
7c57a4cf
 	}
a27b4b8c
 	return container, nil
 }
 
359b7df5
 // Register makes a container object usable by the daemon as <container.ID>
5d5c8939
 // This is a wrapper for register
359b7df5
 func (daemon *Daemon) Register(container *Container) error {
34bd2d62
 	return daemon.register(container, true, nil)
5d5c8939
 }
 
 // register makes a container object usable by the daemon as <container.ID>
34bd2d62
 func (daemon *Daemon) register(container *Container, updateSuffixarray bool, containersToStart *[]*Container) error {
359b7df5
 	if container.daemon != nil || daemon.Exists(container.ID) {
7c57a4cf
 		return fmt.Errorf("Container is already loaded")
 	}
fd224ee5
 	if err := validateID(container.ID); err != nil {
7c57a4cf
 		return err
 	}
359b7df5
 	if err := daemon.ensureName(container); err != nil {
a9ed238b
 		return err
 	}
3dcaf20d
 
359b7df5
 	container.daemon = daemon
329f4449
 
7c57a4cf
 	// Attach to stdout and stderr
2e69e172
 	container.stderr = utils.NewWriteBroadcaster()
 	container.stdout = utils.NewWriteBroadcaster()
7c57a4cf
 	// Attach to stdin
 	if container.Config.OpenStdin {
 		container.stdin, container.stdinPipe = io.Pipe()
 	} else {
2e69e172
 		container.stdinPipe = utils.NopWriteCloser(ioutil.Discard) // Silently drop stdin
7c57a4cf
 	}
 	// done
af17b01a
 	daemon.containers.Add(container.ID, container)
5d5c8939
 
 	// don't update the Suffixarray if we're starting up
 	// we'll waste time if we update it for every container
 	if updateSuffixarray {
 		daemon.idIndex.Add(container.ID)
 	} else {
 		daemon.idIndex.AddWithoutSuffixarrayUpdate(container.ID)
 	}
82848d41
 
50144aeb
 	// FIXME: if the container is supposed to be running but is not, auto restart it?
 	//        if so, then we need to restart monitor and init a new lock
 	// If the container is supposed to be running, make sure of it
33e70864
 	if container.State.IsRunning() {
cf997aa9
 		utils.Debugf("killing old running container %s", container.ID)
 
 		existingPid := container.State.Pid
 		container.State.SetStopped(0)
 
 		// We only have to handle this for lxc because the other drivers will ensure that
 		// no processes are left when docker dies
 		if container.ExecDriver == "" || strings.Contains(container.ExecDriver, "lxc") {
 			lxc.KillLxc(container.ID, 9)
 		} else {
 			// use the current driver and ensure that the container is dead x.x
 			cmd := &execdriver.Command{
 				ID: container.ID,
772ef99d
 			}
cf997aa9
 			var err error
 			cmd.Process, err = os.FindProcess(existingPid)
 			if err != nil {
 				utils.Debugf("cannot find existing process for %d", existingPid)
e36d89b0
 			}
cf997aa9
 			daemon.execDriver.Terminate(cmd)
 		}
 		if err := container.Unmount(); err != nil {
 			utils.Debugf("unmount error %s", err)
 		}
 		if err := container.ToDisk(); err != nil {
 			utils.Debugf("saving stopped state to disk %s", err)
772ef99d
 		}
 
359b7df5
 		info := daemon.execDriver.Info(container.ID)
889b4b10
 		if !info.IsRunning() {
9c153228
 			utils.Debugf("Container %s was supposed to be running but is not.", container.ID)
359b7df5
 			if daemon.config.AutoRestart {
34bd2d62
 				utils.Debugf("Marking as restarting")
772ef99d
 				if err := container.Unmount(); err != nil {
 					utils.Debugf("restart unmount error %s", err)
 				}
 
34bd2d62
 				if containersToStart != nil {
 					*containersToStart = append(*containersToStart, container)
86ada2fa
 				}
 			} else {
 				utils.Debugf("Marking as stopped")
33e70864
 				container.State.SetStopped(-127)
86ada2fa
 				if err := container.ToDisk(); err != nil {
 					return err
50144aeb
 				}
 			}
3cbec951
 		}
0376a69c
 	} else {
 		// When the container is not running, we still initialize the waitLock
 		// chan and close it. Receiving on nil chan blocks whereas receiving on a
 		// closed chan does not. In this case we do not want to block.
 		container.waitLock = make(chan struct{})
 		close(container.waitLock)
82848d41
 	}
7c57a4cf
 	return nil
 }
 
359b7df5
 func (daemon *Daemon) ensureName(container *Container) error {
a9ed238b
 	if container.Name == "" {
6ec86cb6
 		name, err := daemon.generateNewName(container.ID)
a9ed238b
 		if err != nil {
6ec86cb6
 			return err
a9ed238b
 		}
 		container.Name = name
 
 		if err := container.ToDisk(); err != nil {
 			utils.Debugf("Error saving container name %s", err)
 		}
 	}
 	return nil
 }
 
359b7df5
 func (daemon *Daemon) LogToDisk(src *utils.WriteBroadcaster, dst, stream string) error {
7c57a4cf
 	log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
 	if err != nil {
 		return err
 	}
941e3e2e
 	src.AddWriter(log, stream)
7c57a4cf
 	return nil
 }
 
359b7df5
 // Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
 func (daemon *Daemon) Destroy(container *Container) error {
42b1ea48
 	if container == nil {
 		return fmt.Errorf("The given container is <nil>")
 	}
 
af17b01a
 	element := daemon.containers.Get(container.ID)
a27b4b8c
 	if element == nil {
fd224ee5
 		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
a27b4b8c
 	}
 
28fd289b
 	if err := container.Stop(3); err != nil {
a27b4b8c
 		return err
 	}
1cbdaeba
 
9f152aac
 	// Deregister the container before removing its directory, to avoid race conditions
 	daemon.idIndex.Delete(container.ID)
af17b01a
 	daemon.containers.Delete(container.ID)
9f152aac
 
c12dd770
 	if _, err := daemon.containerGraph.Purge(container.ID); err != nil {
 		utils.Debugf("Unable to remove container from link graph: %s", err)
 	}
 
359b7df5
 	if err := daemon.driver.Remove(container.ID); err != nil {
 		return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.driver, container.ID, err)
fcc0af9f
 	}
1cbdaeba
 
5976c26c
 	initID := fmt.Sprintf("%s-init", container.ID)
359b7df5
 	if err := daemon.driver.Remove(initID); err != nil {
 		return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", daemon.driver, initID, err)
5976c26c
 	}
 
7c57a4cf
 	if err := os.RemoveAll(container.root); err != nil {
fd224ee5
 		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
a27b4b8c
 	}
b7942ec2
 	selinux.FreeLxcContexts(container.ProcessLabel)
 
a27b4b8c
 	return nil
 }
 
359b7df5
 func (daemon *Daemon) restore() error {
34bd2d62
 	var (
 		debug             = (os.Getenv("DEBUG") != "" || os.Getenv("TEST") != "")
 		containers        = make(map[string]*Container)
 		currentDriver     = daemon.driver.String()
 		containersToStart = []*Container{}
 	)
0fd0deb7
 
 	if !debug {
fde909ff
 		fmt.Printf("Loading containers: ")
20b1e196
 	}
359b7df5
 	dir, err := ioutil.ReadDir(daemon.repository)
a27b4b8c
 	if err != nil {
 		return err
 	}
356af154
 
fde909ff
 	for _, v := range dir {
7c57a4cf
 		id := v.Name()
359b7df5
 		container, err := daemon.load(id)
0fd0deb7
 		if !debug {
fde909ff
 			fmt.Print(".")
20b1e196
 		}
a27b4b8c
 		if err != nil {
ad723bbf
 			utils.Errorf("Failed to load container %v: %v", id, err)
a27b4b8c
 			continue
 		}
4908d7f8
 
 		// Ignore the container if it does not support the current driver being used by the graph
 		if container.Driver == "" && currentDriver == "aufs" || container.Driver == currentDriver {
 			utils.Debugf("Loaded container %v", container.ID)
 			containers[container.ID] = container
 		} else {
 			utils.Debugf("Cannot load container %s because it was created with another graph driver.", container.ID)
 		}
1cbdaeba
 	}
 
359b7df5
 	if entities := daemon.containerGraph.List("/", -1); entities != nil {
356af154
 		for _, p := range entities.Paths() {
0fd0deb7
 			if !debug {
fde909ff
 				fmt.Print(".")
 			}
356af154
 			e := entities[p]
 			if container, ok := containers[e.ID()]; ok {
34bd2d62
 				if err := daemon.register(container, false, &containersToStart); err != nil {
0fd0deb7
 					utils.Debugf("Failed to register container %s: %s", container.ID, err)
 				}
356af154
 				delete(containers, e.ID())
 			}
1cbdaeba
 		}
356af154
 	}
2e6b241d
 
356af154
 	// Any containers that are left over do not exist in the graph
 	for _, container := range containers {
2e6b241d
 		// Try to set the default name for a container if it exists prior to links
6ec86cb6
 		container.Name, err = daemon.generateNewName(container.ID)
8227ea35
 		if err != nil {
2e6b241d
 			utils.Debugf("Setting default id - %s", err)
 		}
34bd2d62
 		if err := daemon.register(container, false, &containersToStart); err != nil {
0fd0deb7
 			utils.Debugf("Failed to register container %s: %s", container.ID, err)
 		}
a27b4b8c
 	}
356af154
 
5d5c8939
 	daemon.idIndex.UpdateSuffixarray()
34bd2d62
 
 	for _, container := range containersToStart {
 		utils.Debugf("Starting container %d", container.ID)
 		if err := container.Start(); err != nil {
 			utils.Debugf("Failed to start container %s: %s", container.ID, err)
 		}
 	}
 
0fd0deb7
 	if !debug {
fde909ff
 		fmt.Printf(": done.\n")
20b1e196
 	}
1cbdaeba
 
a27b4b8c
 	return nil
 }
 
0d292440
 // Create creates a new container from the given configuration with a given name.
359b7df5
 func (daemon *Daemon) Create(config *runconfig.Config, name string) (*Container, []string, error) {
12778854
 	var (
 		container *Container
 		warnings  []string
 	)
 
359b7df5
 	img, err := daemon.repositories.LookupImage(config.Image)
24e02043
 	if err != nil {
1cbdaeba
 		return nil, nil, err
24e02043
 	}
359b7df5
 	if err := daemon.checkImageDepth(img); err != nil {
12778854
 		return nil, nil, err
 	}
359b7df5
 	if warnings, err = daemon.mergeAndVerifyConfig(config, img); err != nil {
12778854
 		return nil, nil, err
 	}
359b7df5
 	if container, err = daemon.newContainer(name, config, img); err != nil {
12778854
 		return nil, nil, err
 	}
359b7df5
 	if err := daemon.createRootfs(container, img); err != nil {
12778854
 		return nil, nil, err
 	}
 	if err := container.ToDisk(); err != nil {
 		return nil, nil, err
 	}
359b7df5
 	if err := daemon.Register(container); err != nil {
12778854
 		return nil, nil, err
 	}
 	return container, warnings, nil
 }
24e02043
 
359b7df5
 func (daemon *Daemon) checkImageDepth(img *image.Image) error {
af753cba
 	// We add 2 layers to the depth because the container's rw and
 	// init layer add to the restriction
 	depth, err := img.Depth()
 	if err != nil {
12778854
 		return err
af753cba
 	}
 	if depth+2 >= MaxImageDepth {
12778854
 		return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
af753cba
 	}
12778854
 	return nil
 }
af753cba
 
359b7df5
 func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool {
12778854
 	if config != nil {
 		if config.PortSpecs != nil {
 			for _, p := range config.PortSpecs {
 				if strings.Contains(p, ":") {
 					return true
ee814055
 				}
 			}
5bd0437e
 		}
24e02043
 	}
12778854
 	return false
 }
ee814055
 
359b7df5
 func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image.Image) ([]string, error) {
b2503a72
 	warnings := []string{}
359b7df5
 	if daemon.checkDeprecatedExpose(img.Config) || daemon.checkDeprecatedExpose(config) {
2275c833
 		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.")
ee814055
 	}
 	if img.Config != nil {
6393c383
 		if err := runconfig.Merge(config, img.Config); err != nil {
12778854
 			return nil, err
b2503a72
 		}
 	}
44821158
 	if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 {
12778854
 		return nil, fmt.Errorf("No command specified")
24e02043
 	}
12778854
 	return warnings, nil
 }
24e02043
 
359b7df5
 func (daemon *Daemon) generateIdAndName(name string) (string, string, error) {
12778854
 	var (
 		err error
 		id  = utils.GenerateRandomID()
 	)
1cbdaeba
 
0d292440
 	if name == "" {
6ec86cb6
 		if name, err = daemon.generateNewName(id); err != nil {
 			return "", "", err
f63cdf02
 		}
6ec86cb6
 		return id, name, nil
 	}
 
 	if name, err = daemon.reserveName(id, name); err != nil {
 		return "", "", err
 	}
 
 	return id, name, nil
 }
 
 func (daemon *Daemon) reserveName(id, name string) (string, error) {
 	if !validContainerNamePattern.MatchString(name) {
 		return "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars)
0d292440
 	}
6ec86cb6
 
0d292440
 	if name[0] != '/' {
 		name = "/" + name
 	}
6ec86cb6
 
359b7df5
 	if _, err := daemon.containerGraph.Set(name, id); err != nil {
e8af7fcf
 		if !graphdb.IsNonUniqueNameError(err) {
6ec86cb6
 			return "", err
7bf3a073
 		}
 
359b7df5
 		conflictingContainer, err := daemon.GetByName(name)
7bf3a073
 		if err != nil {
 			if strings.Contains(err.Error(), "Could not find entity") {
6ec86cb6
 				return "", err
7bf3a073
 			}
 
 			// Remove name and continue starting the container
359b7df5
 			if err := daemon.containerGraph.Delete(name); err != nil {
6ec86cb6
 				return "", err
7bf3a073
 			}
 		} else {
1cb7b9ad
 			nameAsKnownByUser := strings.TrimPrefix(name, "/")
6ec86cb6
 			return "", fmt.Errorf(
7bf3a073
 				"Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", nameAsKnownByUser,
 				utils.TruncateID(conflictingContainer.ID), nameAsKnownByUser)
8fa6e2b1
 		}
1cbdaeba
 	}
6ec86cb6
 	return name, nil
 }
 
 func (daemon *Daemon) generateNewName(id string) (string, error) {
 	var name string
e70a5ab0
 	for i := 0; i < 6; i++ {
6ec86cb6
 		name = namesgenerator.GetRandomName(i)
 		if name[0] != '/' {
 			name = "/" + name
 		}
 
 		if _, err := daemon.containerGraph.Set(name, id); err != nil {
 			if !graphdb.IsNonUniqueNameError(err) {
 				return "", err
 			}
 			continue
 		}
 		return name, nil
 	}
 
 	name = "/" + utils.TruncateID(id)
 	if _, err := daemon.containerGraph.Set(name, id); err != nil {
 		return "", err
 	}
 	return name, nil
12778854
 }
1cbdaeba
 
359b7df5
 func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
24e02043
 	// Generate default hostname
 	// FIXME: the lxc template no longer needs to set a default hostname
 	if config.Hostname == "" {
 		config.Hostname = id[:12]
 	}
12778854
 }
24e02043
 
359b7df5
 func (daemon *Daemon) getEntrypointAndArgs(config *runconfig.Config) (string, []string) {
12778854
 	var (
 		entrypoint string
 		args       []string
 	)
24e02043
 	if len(config.Entrypoint) != 0 {
 		entrypoint = config.Entrypoint[0]
 		args = append(config.Entrypoint[1:], config.Cmd...)
 	} else {
 		entrypoint = config.Cmd[0]
 		args = config.Cmd[1:]
 	}
12778854
 	return entrypoint, args
 }
 
359b7df5
 func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *image.Image) (*Container, error) {
12778854
 	var (
 		id  string
 		err error
 	)
359b7df5
 	id, name, err = daemon.generateIdAndName(name)
12778854
 	if err != nil {
 		return nil, err
 	}
 
359b7df5
 	daemon.generateHostname(id, config)
 	entrypoint, args := daemon.getEntrypointAndArgs(config)
24e02043
 
 	container := &Container{
 		// FIXME: we should generate the ID here instead of receiving it as an argument
 		ID:              id,
806abe90
 		Created:         time.Now().UTC(),
24e02043
 		Path:            entrypoint,
 		Args:            args, //FIXME: de-duplicate from config
 		Config:          config,
6393c383
 		hostConfig:      &runconfig.HostConfig{},
24e02043
 		Image:           img.ID, // Always use the resolved image id
 		NetworkSettings: &NetworkSettings{},
45d7dcfe
 		Name:            name,
359b7df5
 		Driver:          daemon.driver.String(),
 		ExecDriver:      daemon.execDriver.Name(),
24e02043
 	}
359b7df5
 	container.root = daemon.containerRoot(container.ID)
46e05ed2
 
1a5ffef6
 	if container.ProcessLabel, container.MountLabel, err = label.GenLabels(""); err != nil {
46e05ed2
 		return nil, err
 	}
12778854
 	return container, nil
 }
 
359b7df5
 func (daemon *Daemon) createRootfs(container *Container, img *image.Image) error {
24e02043
 	// Step 1: create the container directory.
 	// This doubles as a barrier to avoid race conditions.
 	if err := os.Mkdir(container.root, 0700); err != nil {
12778854
 		return err
24e02043
 	}
f2bab155
 	initID := fmt.Sprintf("%s-init", container.ID)
f0e6e135
 	if err := daemon.driver.Create(initID, img.ID); err != nil {
12778854
 		return err
f2bab155
 	}
f0e6e135
 	initPath, err := daemon.driver.Get(initID, "")
f2bab155
 	if err != nil {
12778854
 		return err
f2bab155
 	}
359b7df5
 	defer daemon.driver.Put(initID)
bcaf6c23
 
01b6b2be
 	if err := graph.SetupInitLayer(initPath); err != nil {
12778854
 		return err
f2bab155
 	}
 
f0e6e135
 	if err := daemon.driver.Create(container.ID, initID); err != nil {
12778854
 		return err
f2bab155
 	}
12778854
 	return nil
 }
 
24e02043
 // Commit creates a new filesystem image from the current state of a container.
 // The image can optionally be tagged into a repository
359b7df5
 func (daemon *Daemon) Commit(container *Container, repository, tag, comment, author string, config *runconfig.Config) (*image.Image, error) {
24e02043
 	// FIXME: freeze the container before copying it to avoid data corruption?
191aa17d
 	if err := container.Mount(); err != nil {
24e02043
 		return nil, err
 	}
bcaf6c23
 	defer container.Unmount()
24e02043
 
 	rwTar, err := container.ExportRw()
 	if err != nil {
 		return nil, err
 	}
f198ee52
 	defer rwTar.Close()
 
24e02043
 	// Create a new image from the container's base layers + a new layer from container changes
01b6b2be
 	var (
 		containerID, containerImage string
 		containerConfig             *runconfig.Config
 	)
e454be75
 
01b6b2be
 	if container != nil {
 		containerID = container.ID
 		containerImage = container.Image
 		containerConfig = container.Config
 	}
e454be75
 
359b7df5
 	img, err := daemon.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config)
24e02043
 	if err != nil {
 		return nil, err
 	}
e454be75
 
24e02043
 	// Register the image if needed
 	if repository != "" {
359b7df5
 		if err := daemon.repositories.Set(repository, tag, img.ID, true); err != nil {
24e02043
 			return img, err
 		}
 	}
 	return img, nil
 }
 
36c3614f
 func GetFullContainerName(name string) (string, error) {
a9ed238b
 	if name == "" {
 		return "", fmt.Errorf("Container name cannot be empty")
 	}
356af154
 	if name[0] != '/' {
 		name = "/" + name
 	}
a9ed238b
 	return name, nil
356af154
 }
 
359b7df5
 func (daemon *Daemon) GetByName(name string) (*Container, error) {
36c3614f
 	fullName, err := GetFullContainerName(name)
a9ed238b
 	if err != nil {
 		return nil, err
 	}
359b7df5
 	entity := daemon.containerGraph.Get(fullName)
1cbdaeba
 	if entity == nil {
 		return nil, fmt.Errorf("Could not find entity for %s", name)
 	}
af17b01a
 	e := daemon.containers.Get(entity.ID())
1cbdaeba
 	if e == nil {
 		return nil, fmt.Errorf("Could not find container for entity id %s", entity.ID())
 	}
af17b01a
 	return e, nil
1cbdaeba
 }
 
359b7df5
 func (daemon *Daemon) Children(name string) (map[string]*Container, error) {
36c3614f
 	name, err := GetFullContainerName(name)
a9ed238b
 	if err != nil {
 		return nil, err
 	}
1cbdaeba
 	children := make(map[string]*Container)
 
359b7df5
 	err = daemon.containerGraph.Walk(name, func(p string, e *graphdb.Entity) error {
 		c := daemon.Get(e.ID())
1cbdaeba
 		if c == nil {
 			return fmt.Errorf("Could not get container for name %s and id %s", e.ID(), p)
 		}
 		children[p] = c
 		return nil
 	}, 0)
 
 	if err != nil {
 		return nil, err
 	}
 	return children, nil
 }
 
359b7df5
 func (daemon *Daemon) RegisterLink(parent, child *Container, alias string) error {
0d292440
 	fullName := path.Join(parent.Name, alias)
359b7df5
 	if !daemon.containerGraph.Exists(fullName) {
 		_, err := daemon.containerGraph.Set(fullName, child.ID)
1cbdaeba
 		return err
 	}
0d292440
 	return nil
1cbdaeba
 }
 
100a9214
 func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.HostConfig) error {
 	if hostConfig != nil && hostConfig.Links != nil {
 		for _, l := range hostConfig.Links {
 			parts, err := utils.PartParser("name:alias", l)
 			if err != nil {
 				return err
 			}
 			child, err := daemon.GetByName(parts["name"])
 			if err != nil {
 				return err
 			}
 			if child == nil {
 				return fmt.Errorf("Could not get container for %s", parts["name"])
 			}
 			if err := daemon.RegisterLink(container, child, parts["alias"]); err != nil {
 				return err
 			}
 		}
 
 		// After we load all the links into the daemon
 		// set them to nil on the hostconfig
 		hostConfig.Links = nil
 		if err := container.WriteHostConfig(); err != nil {
 			return err
 		}
 	}
 	return nil
 }
 
0b9a3c86
 // FIXME: harmonize with NewGraph()
359b7df5
 func NewDaemon(config *daemonconfig.Config, eng *engine.Engine) (*Daemon, error) {
 	daemon, err := NewDaemonFromDirectory(config, eng)
003622c8
 	if err != nil {
 		return nil, err
 	}
359b7df5
 	return daemon, nil
a27b4b8c
 }
 
359b7df5
 func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*Daemon, error) {
82f37b87
 	if !config.EnableSelinuxSupport {
 		selinux.SetDisabled()
 	}
b4ccd7cb
 
 	// Create the root directory if it doesn't exists
 	if err := os.MkdirAll(config.Root, 0700); err != nil && !os.IsExist(err) {
 		return nil, err
 	}
 
6dbeed89
 	// Set the default driver
 	graphdriver.DefaultDriver = config.GraphDriver
 
f2bab155
 	// Load storage driver
822ea97f
 	driver, err := graphdriver.New(config.Root, config.GraphOptions)
f2bab155
 	if err != nil {
 		return nil, err
 	}
12ffead7
 	utils.Debugf("Using graph driver %s", driver)
f2bab155
 
359b7df5
 	daemonRepo := path.Join(config.Root, "containers")
06553a75
 
359b7df5
 	if err := os.MkdirAll(daemonRepo, 0700); err != nil && !os.IsExist(err) {
06553a75
 		return nil, err
 	}
 
670ce98c
 	// Migrate the container if it is aufs and aufs is enabled
 	if err = migrateIfAufs(driver, config.Root); err != nil {
 		return nil, err
a518b847
 	}
 
fde909ff
 	utils.Debugf("Creating images graph")
01b6b2be
 	g, err := graph.NewGraph(path.Join(config.Root, "graph"), driver)
2ebf3464
 	if err != nil {
 		return nil, err
 	}
10f23a94
 
 	// We don't want to use a complex driver like aufs or devmapper
 	// for volumes, just a plain filesystem
822ea97f
 	volumesDriver, err := graphdriver.GetDriver("vfs", config.Root, config.GraphOptions)
1df5f409
 	if err != nil {
 		return nil, err
 	}
fde909ff
 	utils.Debugf("Creating volumes graph")
01b6b2be
 	volumes, err := graph.NewGraph(path.Join(config.Root, "volumes"), volumesDriver)
1df5f409
 	if err != nil {
 		return nil, err
 	}
fde909ff
 	utils.Debugf("Creating repository list")
01b6b2be
 	repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), g)
44faa07b
 	if err != nil {
 		return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
 	}
c712e74b
 
 	if !config.DisableNetwork {
 		job := eng.Job("init_networkdriver")
 
 		job.SetenvBool("EnableIptables", config.EnableIptables)
 		job.SetenvBool("InterContainerCommunication", config.InterContainerCommunication)
 		job.SetenvBool("EnableIpForward", config.EnableIpForward)
 		job.Setenv("BridgeIface", config.BridgeIface)
 		job.Setenv("BridgeIP", config.BridgeIP)
2d870969
 		job.Setenv("DefaultBindingIP", config.DefaultIp.String())
c712e74b
 
 		if err := job.Run(); err != nil {
 			return nil, err
 		}
1b370f9d
 	}
1cbdaeba
 
cbd1281e
 	graphdbPath := path.Join(config.Root, "linkgraph.db")
329d1542
 	graph, err := graphdb.NewSqliteConn(graphdbPath)
c08f5b2b
 	if err != nil {
 		return nil, err
 	}
1cbdaeba
 
da04f49b
 	localCopy := path.Join(config.Root, "init", fmt.Sprintf("dockerinit-%s", dockerversion.VERSION))
110c4f20
 	sysInitPath := utils.DockerInitPath(localCopy)
 	if sysInitPath == "" {
 		return nil, fmt.Errorf("Could not locate dockerinit: This usually means docker was built incorrectly. See http://docs.docker.io/en/latest/contributing/devenvironment for official build instructions.")
 	}
 
2035af44
 	if sysInitPath != localCopy {
 		// 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).
 		if err := os.Mkdir(path.Dir(localCopy), 0700); err != nil && !os.IsExist(err) {
110c4f20
 			return nil, err
 		}
 		if _, err := utils.CopyFile(sysInitPath, localCopy); err != nil {
 			return nil, err
 		}
2035af44
 		if err := os.Chmod(localCopy, 0700); err != nil {
110c4f20
 			return nil, err
 		}
2035af44
 		sysInitPath = localCopy
110c4f20
 	}
 
07c35b41
 	sysInfo := sysinfo.New(false)
6c266c4b
 	ed, err := execdrivers.NewDriver(config.ExecDriver, config.Root, sysInitPath, sysInfo)
f2680e5a
 	if err != nil {
 		return nil, err
 	}
 
359b7df5
 	daemon := &Daemon{
 		repository:     daemonRepo,
af17b01a
 		containers:     &contStore{s: make(map[string]*Container)},
44faa07b
 		graph:          g,
 		repositories:   repositories,
4f169c2d
 		idIndex:        utils.NewTruncIndex([]string{}),
9e9f4b92
 		sysInfo:        sysInfo,
1df5f409
 		volumes:        volumes,
1cbdaeba
 		config:         config,
 		containerGraph: graph,
f1127b93
 		driver:         driver,
110c4f20
 		sysInitPath:    sysInitPath,
f2680e5a
 		execDriver:     ed,
49b98130
 		eng:            eng,
a27b4b8c
 	}
 
359b7df5
 	if err := daemon.checkLocaldns(); err != nil {
919dbbe4
 		return nil, err
 	}
359b7df5
 	if err := daemon.restore(); err != nil {
a27b4b8c
 		return nil, err
 	}
359b7df5
 	return daemon, nil
a27b4b8c
 }
f8f9285c
 
359b7df5
 func (daemon *Daemon) shutdown() error {
f067e263
 	group := sync.WaitGroup{}
 	utils.Debugf("starting clean shutdown of all containers...")
359b7df5
 	for _, container := range daemon.List() {
93779cc7
 		c := container
 		if c.State.IsRunning() {
 			utils.Debugf("stopping %s", c.ID)
f067e263
 			group.Add(1)
 
 			go func() {
 				defer group.Done()
93779cc7
 				if err := c.KillSig(15); err != nil {
 					utils.Debugf("kill 15 error for %s - %s", c.ID, err)
 				}
 				c.Wait()
 				utils.Debugf("container stopped %s", c.ID)
f067e263
 			}()
 		}
 	}
 	group.Wait()
 
 	return nil
 }
 
359b7df5
 func (daemon *Daemon) Close() error {
43899a77
 	errorsStrings := []string{}
359b7df5
 	if err := daemon.shutdown(); err != nil {
 		utils.Errorf("daemon.shutdown(): %s", err)
f067e263
 		errorsStrings = append(errorsStrings, err.Error())
 	}
da61b99b
 	if err := portallocator.ReleaseAll(); err != nil {
 		utils.Errorf("portallocator.ReleaseAll(): %s", err)
43899a77
 		errorsStrings = append(errorsStrings, err.Error())
 	}
359b7df5
 	if err := daemon.driver.Cleanup(); err != nil {
 		utils.Errorf("daemon.driver.Cleanup(): %s", err.Error())
43899a77
 		errorsStrings = append(errorsStrings, err.Error())
 	}
359b7df5
 	if err := daemon.containerGraph.Close(); err != nil {
 		utils.Errorf("daemon.containerGraph.Close(): %s", err.Error())
43899a77
 		errorsStrings = append(errorsStrings, err.Error())
 	}
 	if len(errorsStrings) > 0 {
 		return fmt.Errorf("%s", strings.Join(errorsStrings, ", "))
 	}
 	return nil
7c08aeeb
 }
 
359b7df5
 func (daemon *Daemon) Mount(container *Container) error {
1a5ffef6
 	dir, err := daemon.driver.Get(container.ID, container.GetMountLabel())
699a1074
 	if err != nil {
359b7df5
 		return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, daemon.driver, err)
f2bab155
 	}
fab19d19
 	if container.basefs == "" {
 		container.basefs = dir
 	} else if container.basefs != dir {
f2bab155
 		return fmt.Errorf("Error: driver %s is returning inconsistent paths for container %s ('%s' then '%s')",
359b7df5
 			daemon.driver, container.ID, container.basefs, dir)
699a1074
 	}
f2bab155
 	return nil
699a1074
 }
 
359b7df5
 func (daemon *Daemon) Unmount(container *Container) error {
 	daemon.driver.Put(container.ID)
f2bab155
 	return nil
699a1074
 }
 
359b7df5
 func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) {
 	if differ, ok := daemon.driver.(graphdriver.Differ); ok {
5d972300
 		return differ.Changes(container.ID)
 	}
f0e6e135
 	cDir, err := daemon.driver.Get(container.ID, "")
5d972300
 	if err != nil {
359b7df5
 		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
5d972300
 	}
359b7df5
 	defer daemon.driver.Put(container.ID)
f0e6e135
 	initDir, err := daemon.driver.Get(container.ID+"-init", "")
5d972300
 	if err != nil {
359b7df5
 		return nil, fmt.Errorf("Error getting container init rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
5d972300
 	}
359b7df5
 	defer daemon.driver.Put(container.ID + "-init")
5d972300
 	return archive.ChangesDirs(cDir, initDir)
699a1074
 }
 
359b7df5
 func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) {
 	if differ, ok := daemon.driver.(graphdriver.Differ); ok {
5d972300
 		return differ.Diff(container.ID)
 	}
 
359b7df5
 	changes, err := daemon.Changes(container)
5d972300
 	if err != nil {
 		return nil, err
 	}
 
f0e6e135
 	cDir, err := daemon.driver.Get(container.ID, "")
5d972300
 	if err != nil {
359b7df5
 		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
5d972300
 	}
 
bcaf6c23
 	archive, err := archive.ExportChanges(cDir, changes)
 	if err != nil {
 		return nil, err
 	}
f198ee52
 	return utils.NewReadCloserWrapper(archive, func() error {
 		err := archive.Close()
359b7df5
 		daemon.driver.Put(container.ID)
f198ee52
 		return err
 	}), nil
7c08aeeb
 }
 
359b7df5
 func (daemon *Daemon) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
 	return daemon.execDriver.Run(c.command, pipes, startCallback)
5a3d9bd4
 }
 
b054569c
 func (daemon *Daemon) Pause(c *Container) error {
26246ebd
 	if err := daemon.execDriver.Pause(c.command); err != nil {
b054569c
 		return err
 	}
 	c.State.SetPaused()
 	return nil
 }
 
 func (daemon *Daemon) Unpause(c *Container) error {
26246ebd
 	if err := daemon.execDriver.Unpause(c.command); err != nil {
b054569c
 		return err
 	}
 	c.State.SetUnpaused()
 	return nil
 }
 
359b7df5
 func (daemon *Daemon) Kill(c *Container, sig int) error {
 	return daemon.execDriver.Kill(c.command, sig)
5a3d9bd4
 }
 
359a6f49
 // Nuke kills all containers then removes all content
 // from the content root, including images, volumes and
 // container filesystems.
359b7df5
 // Again: this will remove your entire docker daemon!
 func (daemon *Daemon) Nuke() error {
359a6f49
 	var wg sync.WaitGroup
359b7df5
 	for _, container := range daemon.List() {
359a6f49
 		wg.Add(1)
 		go func(c *Container) {
 			c.Kill()
 			wg.Done()
 		}(container)
 	}
 	wg.Wait()
359b7df5
 	daemon.Close()
359a6f49
 
359b7df5
 	return os.RemoveAll(daemon.config.Root)
359a6f49
 }
 
 // FIXME: this is a convenience function for integration tests
359b7df5
 // which need direct access to daemon.graph.
359a6f49
 // Once the tests switch to using engine and jobs, this method
 // can go away.
359b7df5
 func (daemon *Daemon) Graph() *graph.Graph {
 	return daemon.graph
359a6f49
 }
 
359b7df5
 func (daemon *Daemon) Repositories() *graph.TagStore {
 	return daemon.repositories
36c3614f
 }
 
359b7df5
 func (daemon *Daemon) Config() *daemonconfig.Config {
 	return daemon.config
36c3614f
 }
 
359b7df5
 func (daemon *Daemon) SystemConfig() *sysinfo.SysInfo {
 	return daemon.sysInfo
36c3614f
 }
 
359b7df5
 func (daemon *Daemon) SystemInitPath() string {
 	return daemon.sysInitPath
36c3614f
 }
 
359b7df5
 func (daemon *Daemon) GraphDriver() graphdriver.Driver {
 	return daemon.driver
36c3614f
 }
 
359b7df5
 func (daemon *Daemon) ExecutionDriver() execdriver.Driver {
 	return daemon.execDriver
36c3614f
 }
 
359b7df5
 func (daemon *Daemon) Volumes() *graph.Graph {
 	return daemon.volumes
36c3614f
 }
 
359b7df5
 func (daemon *Daemon) ContainerGraph() *graphdb.Database {
 	return daemon.containerGraph
36c3614f
 }
 
359b7df5
 func (daemon *Daemon) SetServer(server Server) {
 	daemon.srv = server
36c3614f
 }
919dbbe4
 
359b7df5
 func (daemon *Daemon) checkLocaldns() error {
3744452e
 	resolvConf, err := resolvconf.Get()
919dbbe4
 	if err != nil {
 		return err
 	}
359b7df5
 	if len(daemon.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
919dbbe4
 		log.Printf("Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : %v\n", DefaultDns)
359b7df5
 		daemon.config.Dns = DefaultDns
919dbbe4
 	}
 	return nil
 }