123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- // +build daemon
- package main
- import (
- "crypto/tls"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "time"
- "github.com/Sirupsen/logrus"
- apiserver "github.com/docker/docker/api/server"
- "github.com/docker/docker/autogen/dockerversion"
- "github.com/docker/docker/daemon"
- "github.com/docker/docker/pkg/homedir"
- flag "github.com/docker/docker/pkg/mflag"
- "github.com/docker/docker/pkg/pidfile"
- "github.com/docker/docker/pkg/signal"
- "github.com/docker/docker/pkg/timeutils"
- "github.com/docker/docker/pkg/tlsconfig"
- "github.com/docker/docker/registry"
- "github.com/docker/docker/utils"
- )
- var (
- daemonCfg = &daemon.Config{}
- registryCfg = ®istry.Options{}
- )
- func init() {
- if daemonCfg.LogConfig.Config == nil {
- daemonCfg.LogConfig.Config = make(map[string]string)
- }
- daemonCfg.InstallFlags()
- registryCfg.InstallFlags()
- }
- func migrateKey() (err error) {
- // Migrate trust key if exists at ~/.docker/key.json and owned by current user
- oldPath := filepath.Join(homedir.Get(), ".docker", defaultTrustKeyFile)
- newPath := filepath.Join(getDaemonConfDir(), defaultTrustKeyFile)
- if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && currentUserIsOwner(oldPath) {
- defer func() {
- // Ensure old path is removed if no error occurred
- if err == nil {
- err = os.Remove(oldPath)
- } else {
- logrus.Warnf("Key migration failed, key file not removed at %s", oldPath)
- }
- }()
- if err := os.MkdirAll(getDaemonConfDir(), os.FileMode(0644)); err != nil {
- return fmt.Errorf("Unable to create daemon configuration directory: %s", err)
- }
- 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 {
- return fmt.Errorf("error opening key file %q: %s", oldPath, err)
- }
- defer oldFile.Close()
- if _, err := io.Copy(newFile, oldFile); err != nil {
- return fmt.Errorf("error copying key: %s", err)
- }
- logrus.Infof("Migrated key from %s to %s", oldPath, newPath)
- }
- return nil
- }
- func mainDaemon() {
- if utils.ExperimentalBuild() {
- logrus.Warn("Running experimental build")
- }
- if flag.NArg() != 0 {
- flag.Usage()
- return
- }
- logrus.SetFormatter(&logrus.TextFormatter{TimestampFormat: timeutils.RFC3339NanoFixed})
- if err := setDefaultUmask(); err != nil {
- logrus.Fatalf("Failed to set umask: %v", err)
- }
- 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)
- }
- }()
- }
- serverConfig := &apiserver.ServerConfig{
- Logging: true,
- EnableCors: daemonCfg.EnableCors,
- CorsHeaders: daemonCfg.CorsHeaders,
- Version: dockerversion.VERSION,
- }
- serverConfig = setPlatformServerConfig(serverConfig, daemonCfg)
- if *flTls {
- if *flTlsVerify {
- tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
- }
- tlsConfig, err := tlsconfig.Server(tlsOptions)
- if err != nil {
- logrus.Fatal(err)
- }
- serverConfig.TLSConfig = tlsConfig
- }
- api := apiserver.New(serverConfig)
- // The serve API routine never exits unless an error occurs
- // We need to start it as a goroutine and wait on it so
- // daemon doesn't exit
- serveAPIWait := make(chan error)
- go func() {
- if err := api.ServeApi(flHosts); err != nil {
- logrus.Errorf("ServeAPI error: %v", err)
- serveAPIWait <- err
- return
- }
- serveAPIWait <- nil
- }()
- 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")
- signal.Trap(func() {
- api.Close()
- <-serveAPIWait
- shutdownDaemon(d, 15)
- if pfile != nil {
- if err := pfile.Remove(); err != nil {
- logrus.Error(err)
- }
- }
- })
- // after the daemon is done setting up we can tell the api to start
- // accepting connections with specified daemon
- api.AcceptConnections(d)
- // Daemon is fully initialized and handling API traffic
- // Wait for serve API to complete
- errAPI := <-serveAPIWait
- shutdownDaemon(d, 15)
- if errAPI != nil {
- if pfile != nil {
- if err := pfile.Remove(); err != nil {
- logrus.Error(err)
- }
- }
- logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI)
- }
- }
- // 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")
- }
- }
|