github.com/codemac/docker@v1.2.1-0.20150518222241-6a18412d5b9c/docker/daemon.go (about) 1 // +build daemon 2 3 package main 4 5 import ( 6 "fmt" 7 "io" 8 "os" 9 "path/filepath" 10 "time" 11 12 "github.com/Sirupsen/logrus" 13 apiserver "github.com/docker/docker/api/server" 14 "github.com/docker/docker/autogen/dockerversion" 15 "github.com/docker/docker/daemon" 16 _ "github.com/docker/docker/daemon/execdriver/lxc" 17 _ "github.com/docker/docker/daemon/execdriver/native" 18 "github.com/docker/docker/pkg/homedir" 19 flag "github.com/docker/docker/pkg/mflag" 20 "github.com/docker/docker/pkg/pidfile" 21 "github.com/docker/docker/pkg/signal" 22 "github.com/docker/docker/pkg/system" 23 "github.com/docker/docker/pkg/timeutils" 24 "github.com/docker/docker/registry" 25 ) 26 27 const CanDaemon = true 28 29 var ( 30 daemonCfg = &daemon.Config{} 31 registryCfg = ®istry.Options{} 32 ) 33 34 func init() { 35 if daemonCfg.LogConfig.Config == nil { 36 daemonCfg.LogConfig.Config = make(map[string]string) 37 } 38 daemonCfg.InstallFlags() 39 registryCfg.InstallFlags() 40 } 41 42 func migrateKey() (err error) { 43 // Migrate trust key if exists at ~/.docker/key.json and owned by current user 44 oldPath := filepath.Join(homedir.Get(), ".docker", defaultTrustKeyFile) 45 newPath := filepath.Join(getDaemonConfDir(), defaultTrustKeyFile) 46 if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && currentUserIsOwner(oldPath) { 47 defer func() { 48 // Ensure old path is removed if no error occurred 49 if err == nil { 50 err = os.Remove(oldPath) 51 } else { 52 logrus.Warnf("Key migration failed, key file not removed at %s", oldPath) 53 } 54 }() 55 56 if err := os.MkdirAll(getDaemonConfDir(), os.FileMode(0644)); err != nil { 57 return fmt.Errorf("Unable to create daemon configuration directory: %s", err) 58 } 59 60 newFile, err := os.OpenFile(newPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) 61 if err != nil { 62 return fmt.Errorf("error creating key file %q: %s", newPath, err) 63 } 64 defer newFile.Close() 65 66 oldFile, err := os.Open(oldPath) 67 if err != nil { 68 return fmt.Errorf("error opening key file %q: %s", oldPath, err) 69 } 70 defer oldFile.Close() 71 72 if _, err := io.Copy(newFile, oldFile); err != nil { 73 return fmt.Errorf("error copying key: %s", err) 74 } 75 76 logrus.Infof("Migrated key from %s to %s", oldPath, newPath) 77 } 78 79 return nil 80 } 81 82 func mainDaemon() { 83 if flag.NArg() != 0 { 84 flag.Usage() 85 return 86 } 87 88 logrus.SetFormatter(&logrus.TextFormatter{TimestampFormat: timeutils.RFC3339NanoFixed}) 89 90 var pfile *pidfile.PidFile 91 if daemonCfg.Pidfile != "" { 92 pf, err := pidfile.New(daemonCfg.Pidfile) 93 if err != nil { 94 logrus.Fatalf("Error starting daemon: %v", err) 95 } 96 pfile = pf 97 defer func() { 98 if err := pfile.Remove(); err != nil { 99 logrus.Error(err) 100 } 101 }() 102 } 103 104 serverConfig := &apiserver.ServerConfig{ 105 Logging: true, 106 EnableCors: daemonCfg.EnableCors, 107 CorsHeaders: daemonCfg.CorsHeaders, 108 Version: dockerversion.VERSION, 109 SocketGroup: daemonCfg.SocketGroup, 110 Tls: *flTls, 111 TlsVerify: *flTlsVerify, 112 TlsCa: *flCa, 113 TlsCert: *flCert, 114 TlsKey: *flKey, 115 } 116 117 api := apiserver.New(serverConfig) 118 119 // The serve API routine never exits unless an error occurs 120 // We need to start it as a goroutine and wait on it so 121 // daemon doesn't exit 122 serveAPIWait := make(chan error) 123 go func() { 124 if err := api.ServeApi(flHosts); err != nil { 125 logrus.Errorf("ServeAPI error: %v", err) 126 serveAPIWait <- err 127 return 128 } 129 serveAPIWait <- nil 130 }() 131 132 if err := migrateKey(); err != nil { 133 logrus.Fatal(err) 134 } 135 daemonCfg.TrustKeyPath = *flTrustKey 136 137 registryService := registry.NewService(registryCfg) 138 d, err := daemon.NewDaemon(daemonCfg, registryService) 139 if err != nil { 140 if pfile != nil { 141 if err := pfile.Remove(); err != nil { 142 logrus.Error(err) 143 } 144 } 145 logrus.Fatalf("Error starting daemon: %v", err) 146 } 147 148 logrus.Info("Daemon has completed initialization") 149 150 logrus.WithFields(logrus.Fields{ 151 "version": dockerversion.VERSION, 152 "commit": dockerversion.GITCOMMIT, 153 "execdriver": d.ExecutionDriver().Name(), 154 "graphdriver": d.GraphDriver().String(), 155 }).Info("Docker daemon") 156 157 signal.Trap(func() { 158 api.Close() 159 <-serveAPIWait 160 shutdownDaemon(d, 15) 161 if pfile != nil { 162 if err := pfile.Remove(); err != nil { 163 logrus.Error(err) 164 } 165 } 166 }) 167 168 // after the daemon is done setting up we can tell the api to start 169 // accepting connections with specified daemon 170 api.AcceptConnections(d) 171 172 // Daemon is fully initialized and handling API traffic 173 // Wait for serve API to complete 174 errAPI := <-serveAPIWait 175 shutdownDaemon(d, 15) 176 if errAPI != nil { 177 if pfile != nil { 178 if err := pfile.Remove(); err != nil { 179 logrus.Error(err) 180 } 181 } 182 logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI) 183 } 184 } 185 186 // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case 187 // d.Shutdown() is waiting too long to kill container or worst it's 188 // blocked there 189 func shutdownDaemon(d *daemon.Daemon, timeout time.Duration) { 190 ch := make(chan struct{}) 191 go func() { 192 d.Shutdown() 193 close(ch) 194 }() 195 select { 196 case <-ch: 197 logrus.Debug("Clean shutdown succeded") 198 case <-time.After(timeout * time.Second): 199 logrus.Error("Force shutdown daemon") 200 } 201 } 202 203 // currentUserIsOwner checks whether the current user is the owner of the given 204 // file. 205 func currentUserIsOwner(f string) bool { 206 if fileInfo, err := system.Stat(f); err == nil && fileInfo != nil { 207 if int(fileInfo.Uid()) == os.Getuid() { 208 return true 209 } 210 } 211 return false 212 }