github.com/lmars/docker@v1.6.0-rc2/docker/daemon.go (about) 1 // +build daemon 2 3 package main 4 5 import ( 6 "fmt" 7 "io" 8 "os" 9 "path/filepath" 10 "strings" 11 12 log "github.com/Sirupsen/logrus" 13 "github.com/docker/docker/autogen/dockerversion" 14 "github.com/docker/docker/builder" 15 "github.com/docker/docker/builtins" 16 "github.com/docker/docker/daemon" 17 _ "github.com/docker/docker/daemon/execdriver/lxc" 18 _ "github.com/docker/docker/daemon/execdriver/native" 19 "github.com/docker/docker/engine" 20 "github.com/docker/docker/pkg/homedir" 21 flag "github.com/docker/docker/pkg/mflag" 22 "github.com/docker/docker/pkg/signal" 23 "github.com/docker/docker/registry" 24 "github.com/docker/docker/utils" 25 ) 26 27 const CanDaemon = true 28 29 var ( 30 daemonCfg = &daemon.Config{} 31 registryCfg = ®istry.Options{} 32 ) 33 34 func init() { 35 daemonCfg.InstallFlags() 36 registryCfg.InstallFlags() 37 } 38 39 func migrateKey() (err error) { 40 // Migrate trust key if exists at ~/.docker/key.json and owned by current user 41 oldPath := filepath.Join(homedir.Get(), ".docker", defaultTrustKeyFile) 42 newPath := filepath.Join(getDaemonConfDir(), defaultTrustKeyFile) 43 if _, statErr := os.Stat(newPath); os.IsNotExist(statErr) && utils.IsFileOwner(oldPath) { 44 defer func() { 45 // Ensure old path is removed if no error occurred 46 if err == nil { 47 err = os.Remove(oldPath) 48 } else { 49 log.Warnf("Key migration failed, key file not removed at %s", oldPath) 50 } 51 }() 52 53 if err := os.MkdirAll(getDaemonConfDir(), os.FileMode(0644)); err != nil { 54 return fmt.Errorf("Unable to create daemon configuration directory: %s", err) 55 } 56 57 newFile, err := os.OpenFile(newPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) 58 if err != nil { 59 return fmt.Errorf("error creating key file %q: %s", newPath, err) 60 } 61 defer newFile.Close() 62 63 oldFile, err := os.Open(oldPath) 64 if err != nil { 65 return fmt.Errorf("error opening key file %q: %s", oldPath, err) 66 } 67 defer oldFile.Close() 68 69 if _, err := io.Copy(newFile, oldFile); err != nil { 70 return fmt.Errorf("error copying key: %s", err) 71 } 72 73 log.Infof("Migrated key from %s to %s", oldPath, newPath) 74 } 75 76 return nil 77 } 78 79 func mainDaemon() { 80 if flag.NArg() != 0 { 81 flag.Usage() 82 return 83 } 84 eng := engine.New() 85 signal.Trap(eng.Shutdown) 86 87 if err := migrateKey(); err != nil { 88 log.Fatal(err) 89 } 90 daemonCfg.TrustKeyPath = *flTrustKey 91 92 // Load builtins 93 if err := builtins.Register(eng); err != nil { 94 log.Fatal(err) 95 } 96 97 // load registry service 98 if err := registry.NewService(registryCfg).Install(eng); err != nil { 99 log.Fatal(err) 100 } 101 102 // load the daemon in the background so we can immediately start 103 // the http api so that connections don't fail while the daemon 104 // is booting 105 daemonInitWait := make(chan error) 106 go func() { 107 d, err := daemon.NewDaemon(daemonCfg, eng) 108 if err != nil { 109 daemonInitWait <- err 110 return 111 } 112 113 log.Infof("docker daemon: %s %s; execdriver: %s; graphdriver: %s", 114 dockerversion.VERSION, 115 dockerversion.GITCOMMIT, 116 d.ExecutionDriver().Name(), 117 d.GraphDriver().String(), 118 ) 119 120 if err := d.Install(eng); err != nil { 121 daemonInitWait <- err 122 return 123 } 124 125 b := &builder.BuilderJob{eng, d} 126 b.Install() 127 128 // after the daemon is done setting up we can tell the api to start 129 // accepting connections 130 if err := eng.Job("acceptconnections").Run(); err != nil { 131 daemonInitWait <- err 132 return 133 } 134 daemonInitWait <- nil 135 }() 136 137 // Serve api 138 job := eng.Job("serveapi", flHosts...) 139 job.SetenvBool("Logging", true) 140 job.SetenvBool("EnableCors", daemonCfg.EnableCors) 141 job.Setenv("CorsHeaders", daemonCfg.CorsHeaders) 142 job.Setenv("Version", dockerversion.VERSION) 143 job.Setenv("SocketGroup", daemonCfg.SocketGroup) 144 145 job.SetenvBool("Tls", *flTls) 146 job.SetenvBool("TlsVerify", *flTlsVerify) 147 job.Setenv("TlsCa", *flCa) 148 job.Setenv("TlsCert", *flCert) 149 job.Setenv("TlsKey", *flKey) 150 job.SetenvBool("BufferRequests", true) 151 152 // The serve API job never exits unless an error occurs 153 // We need to start it as a goroutine and wait on it so 154 // daemon doesn't exit 155 serveAPIWait := make(chan error) 156 go func() { 157 if err := job.Run(); err != nil { 158 log.Errorf("ServeAPI error: %v", err) 159 serveAPIWait <- err 160 return 161 } 162 serveAPIWait <- nil 163 }() 164 165 // Wait for the daemon startup goroutine to finish 166 // This makes sure we can actually cleanly shutdown the daemon 167 log.Debug("waiting for daemon to initialize") 168 errDaemon := <-daemonInitWait 169 if errDaemon != nil { 170 eng.Shutdown() 171 outStr := fmt.Sprintf("Shutting down daemon due to errors: %v", errDaemon) 172 if strings.Contains(errDaemon.Error(), "engine is shutdown") { 173 // if the error is "engine is shutdown", we've already reported (or 174 // will report below in API server errors) the error 175 outStr = "Shutting down daemon due to reported errors" 176 } 177 // we must "fatal" exit here as the API server may be happy to 178 // continue listening forever if the error had no impact to API 179 log.Fatal(outStr) 180 } else { 181 log.Info("Daemon has completed initialization") 182 } 183 184 // Daemon is fully initialized and handling API traffic 185 // Wait for serve API job to complete 186 errAPI := <-serveAPIWait 187 // If we have an error here it is unique to API (as daemonErr would have 188 // exited the daemon process above) 189 eng.Shutdown() 190 if errAPI != nil { 191 log.Fatalf("Shutting down due to ServeAPI error: %v", errAPI) 192 } 193 194 }