docker/daemon.go
1b95590d
 // +build daemon
 
 package main
 
 import (
007ef161
 	"fmt"
 	"io"
 	"os"
 	"path/filepath"
531f4122
 	"time"
007ef161
 
6f4d8470
 	"github.com/Sirupsen/logrus"
a0bf80fe
 	apiserver "github.com/docker/docker/api/server"
6871b9b1
 	"github.com/docker/docker/autogen/dockerversion"
63503caf
 	"github.com/docker/docker/daemon"
73210671
 	_ "github.com/docker/docker/daemon/execdriver/lxc"
 	_ "github.com/docker/docker/daemon/execdriver/native"
f9ae2d4f
 	"github.com/docker/docker/pkg/homedir"
1b95590d
 	flag "github.com/docker/docker/pkg/mflag"
531f4122
 	"github.com/docker/docker/pkg/pidfile"
c9f3fd3f
 	"github.com/docker/docker/pkg/signal"
01724c1c
 	"github.com/docker/docker/pkg/system"
711e5803
 	"github.com/docker/docker/pkg/timeutils"
afade423
 	"github.com/docker/docker/registry"
78578125
 	"github.com/docker/docker/utils"
1b95590d
 )
 
 const CanDaemon = true
 
353b7c8e
 var (
568f86eb
 	daemonCfg   = &daemon.Config{}
 	registryCfg = &registry.Options{}
353b7c8e
 )
 
 func init() {
dca9e02b
 	if daemonCfg.LogConfig.Config == nil {
 		daemonCfg.LogConfig.Config = make(map[string]string)
 	}
353b7c8e
 	daemonCfg.InstallFlags()
568f86eb
 	registryCfg.InstallFlags()
353b7c8e
 }
 
d55e977c
 func migrateKey() (err error) {
007ef161
 	// Migrate trust key if exists at ~/.docker/key.json and owned by current user
f9ae2d4f
 	oldPath := filepath.Join(homedir.Get(), ".docker", defaultTrustKeyFile)
007ef161
 	newPath := filepath.Join(getDaemonConfDir(), defaultTrustKeyFile)
01724c1c
 	if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && currentUserIsOwner(oldPath) {
d55e977c
 		defer func() {
 			// Ensure old path is removed if no error occurred
 			if err == nil {
 				err = os.Remove(oldPath)
 			} else {
6f4d8470
 				logrus.Warnf("Key migration failed, key file not removed at %s", oldPath)
d55e977c
 			}
 		}()
 
007ef161
 		if err := os.MkdirAll(getDaemonConfDir(), os.FileMode(0644)); err != nil {
d55e977c
 			return fmt.Errorf("Unable to create daemon configuration directory: %s", err)
007ef161
 		}
 
 		newFile, err := os.OpenFile(newPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
 		if err != nil {
 			return fmt.Errorf("error creating key file %q: %s", newPath, err)
 		}
 		defer newFile.Close()
 
 		oldFile, err := os.Open(oldPath)
 		if err != nil {
d55e977c
 			return fmt.Errorf("error opening key file %q: %s", oldPath, err)
007ef161
 		}
d55e977c
 		defer oldFile.Close()
007ef161
 
 		if _, err := io.Copy(newFile, oldFile); err != nil {
 			return fmt.Errorf("error copying key: %s", err)
 		}
 
6f4d8470
 		logrus.Infof("Migrated key from %s to %s", oldPath, newPath)
007ef161
 	}
 
 	return nil
 }
 
1b95590d
 func mainDaemon() {
78578125
 	if utils.ExperimentalBuild() {
 		logrus.Warn("Running experimental build")
 	}
 
1b95590d
 	if flag.NArg() != 0 {
 		flag.Usage()
 		return
 	}
711e5803
 
 	logrus.SetFormatter(&logrus.TextFormatter{TimestampFormat: timeutils.RFC3339NanoFixed})
 
531f4122
 	var pfile *pidfile.PidFile
 	if daemonCfg.Pidfile != "" {
 		pf, err := pidfile.New(daemonCfg.Pidfile)
 		if err != nil {
 			logrus.Fatalf("Error starting daemon: %v", err)
 		}
 		pfile = pf
 		defer func() {
 			if err := pfile.Remove(); err != nil {
 				logrus.Error(err)
 			}
 		}()
 	}
afade423
 
a0bf80fe
 	serverConfig := &apiserver.ServerConfig{
 		Logging:     true,
 		EnableCors:  daemonCfg.EnableCors,
 		CorsHeaders: daemonCfg.CorsHeaders,
 		Version:     dockerversion.VERSION,
 		SocketGroup: daemonCfg.SocketGroup,
 		Tls:         *flTls,
 		TlsVerify:   *flTlsVerify,
 		TlsCa:       *flCa,
 		TlsCert:     *flCert,
 		TlsKey:      *flKey,
 	}
 
531f4122
 	api := apiserver.New(serverConfig)
d9ed3165
 
a0bf80fe
 	// The serve API routine never exits unless an error occurs
459e58ff
 	// We need to start it as a goroutine and wait on it so
 	// daemon doesn't exit
 	serveAPIWait := make(chan error)
 	go func() {
d9ed3165
 		if err := api.ServeApi(flHosts); err != nil {
6f4d8470
 			logrus.Errorf("ServeAPI error: %v", err)
459e58ff
 			serveAPIWait <- err
 			return
 		}
 		serveAPIWait <- nil
 	}()
0e3f2f2a
 
08230703
 	if err := migrateKey(); err != nil {
 		logrus.Fatal(err)
 	}
 	daemonCfg.TrustKeyPath = *flTrustKey
 
 	registryService := registry.NewService(registryCfg)
 	d, err := daemon.NewDaemon(daemonCfg, registryService)
 	if err != nil {
 		if pfile != nil {
 			if err := pfile.Remove(); err != nil {
 				logrus.Error(err)
 			}
 		}
 		logrus.Fatalf("Error starting daemon: %v", err)
 	}
 
 	logrus.Info("Daemon has completed initialization")
 
 	logrus.WithFields(logrus.Fields{
 		"version":     dockerversion.VERSION,
 		"commit":      dockerversion.GITCOMMIT,
 		"execdriver":  d.ExecutionDriver().Name(),
 		"graphdriver": d.GraphDriver().String(),
 	}).Info("Docker daemon")
 
531f4122
 	signal.Trap(func() {
 		api.Close()
 		<-serveAPIWait
 		shutdownDaemon(d, 15)
 		if pfile != nil {
 			if err := pfile.Remove(); err != nil {
 				logrus.Error(err)
 			}
 		}
 	})
181fea24
 
 	// after the daemon is done setting up we can tell the api to start
d9ed3165
 	// accepting connections with specified daemon
 	api.AcceptConnections(d)
181fea24
 
459e58ff
 	// Daemon is fully initialized and handling API traffic
531f4122
 	// Wait for serve API to complete
459e58ff
 	errAPI := <-serveAPIWait
531f4122
 	shutdownDaemon(d, 15)
459e58ff
 	if errAPI != nil {
531f4122
 		if pfile != nil {
 			if err := pfile.Remove(); err != nil {
 				logrus.Error(err)
 			}
 		}
6f4d8470
 		logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI)
459e58ff
 	}
1b95590d
 }
01724c1c
 
531f4122
 // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
 // d.Shutdown() is waiting too long to kill container or worst it's
 // blocked there
 func shutdownDaemon(d *daemon.Daemon, timeout time.Duration) {
 	ch := make(chan struct{})
 	go func() {
 		d.Shutdown()
 		close(ch)
 	}()
 	select {
 	case <-ch:
 		logrus.Debug("Clean shutdown succeded")
 	case <-time.After(timeout * time.Second):
 		logrus.Error("Force shutdown daemon")
 	}
 }
 
01724c1c
 // currentUserIsOwner checks whether the current user is the owner of the given
 // file.
 func currentUserIsOwner(f string) bool {
 	if fileInfo, err := system.Stat(f); err == nil && fileInfo != nil {
 		if int(fileInfo.Uid()) == os.Getuid() {
 			return true
 		}
 	}
 	return false
 }