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