Merge pull request #12495 from LK4D4/apiserver_refactoring

Refactoring of api/server for reduce engine usage
This commit is contained in:
Phil Estes 2015-04-20 14:10:34 -04:00
commit f0016c5917
9 changed files with 287 additions and 322 deletions

View file

@ -40,10 +40,6 @@ import (
"github.com/docker/docker/utils"
)
var (
activationLock = make(chan struct{})
)
type ServerConfig struct {
Logging bool
EnableCors bool
@ -57,6 +53,75 @@ type ServerConfig struct {
TlsKey string
}
type Server struct {
daemon *daemon.Daemon
cfg *ServerConfig
router *mux.Router
start chan struct{}
// TODO: delete engine
eng *engine.Engine
}
func New(cfg *ServerConfig, eng *engine.Engine) *Server {
srv := &Server{
cfg: cfg,
start: make(chan struct{}),
eng: eng,
}
r := createRouter(srv, eng)
srv.router = r
return srv
}
func (s *Server) SetDaemon(d *daemon.Daemon) {
s.daemon = d
}
type serverCloser interface {
Serve() error
Close() error
}
// ServeApi loops through all of the protocols sent in to docker and spawns
// off a go routine to setup a serving http.Server for each.
func (s *Server) ServeApi(protoAddrs []string) error {
var chErrors = make(chan error, len(protoAddrs))
for _, protoAddr := range protoAddrs {
protoAddrParts := strings.SplitN(protoAddr, "://", 2)
if len(protoAddrParts) != 2 {
return fmt.Errorf("bad format, expected PROTO://ADDR")
}
go func(proto, addr string) {
logrus.Infof("Listening for HTTP on %s (%s)", proto, addr)
srv, err := s.newServer(proto, addr)
if err != nil {
chErrors <- err
return
}
s.eng.OnShutdown(func() {
if err := srv.Close(); err != nil {
logrus.Error(err)
}
})
if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
err = nil
}
chErrors <- err
}(protoAddrParts[0], protoAddrParts[1])
}
for i := 0; i < len(protoAddrs); i++ {
err := <-chErrors
if err != nil {
return err
}
}
return nil
}
type HttpServer struct {
srv *http.Server
l net.Listener
@ -180,19 +245,14 @@ func streamJSON(job *engine.Job, w http.ResponseWriter, flush bool) {
}
}
func getDaemon(eng *engine.Engine) *daemon.Daemon {
return eng.HackGetGlobalVar("httpapi.daemon").(*daemon.Daemon)
}
func postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var config *registry.AuthConfig
err := json.NewDecoder(r.Body).Decode(&config)
r.Body.Close()
if err != nil {
return err
}
d := getDaemon(eng)
status, err := d.RegistryService.Auth(config)
status, err := s.daemon.RegistryService.Auth(config)
if err != nil {
return err
}
@ -201,7 +261,7 @@ func postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter
})
}
func getVersion(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getVersion(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
w.Header().Set("Content-Type", "application/json")
v := &types.Version{
@ -219,7 +279,7 @@ func getVersion(eng *engine.Engine, version version.Version, w http.ResponseWrit
return writeJSON(w, http.StatusOK, v)
}
func postContainersKill(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersKill(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
@ -247,7 +307,7 @@ func postContainersKill(eng *engine.Engine, version version.Version, w http.Resp
}
}
if err = getDaemon(eng).ContainerKill(name, sig); err != nil {
if err = s.daemon.ContainerKill(name, sig); err != nil {
return err
}
@ -255,7 +315,7 @@ func postContainersKill(eng *engine.Engine, version version.Version, w http.Resp
return nil
}
func postContainersPause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersPause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
@ -264,8 +324,7 @@ func postContainersPause(eng *engine.Engine, version version.Version, w http.Res
}
name := vars["name"]
d := getDaemon(eng)
cont, err := d.Get(name)
cont, err := s.daemon.Get(name)
if err != nil {
return err
}
@ -280,7 +339,7 @@ func postContainersPause(eng *engine.Engine, version version.Version, w http.Res
return nil
}
func postContainersUnpause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersUnpause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
@ -289,8 +348,7 @@ func postContainersUnpause(eng *engine.Engine, version version.Version, w http.R
}
name := vars["name"]
d := getDaemon(eng)
cont, err := d.Get(name)
cont, err := s.daemon.Get(name)
if err != nil {
return err
}
@ -305,17 +363,15 @@ func postContainersUnpause(eng *engine.Engine, version version.Version, w http.R
return nil
}
func getContainersExport(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getContainersExport(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
d := getDaemon(eng)
return d.ContainerExport(vars["name"], w)
return s.daemon.ContainerExport(vars["name"], w)
}
func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -327,7 +383,7 @@ func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseW
All: toBool(r.Form.Get("all")),
}
images, err := getDaemon(eng).Repositories().Images(&imagesConfig)
images, err := s.daemon.Repositories().Images(&imagesConfig)
if err != nil {
return err
}
@ -356,7 +412,7 @@ func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseW
return writeJSON(w, http.StatusOK, legacyImages)
}
func getImagesViz(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getImagesViz(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if version.GreaterThan("1.6") {
w.WriteHeader(http.StatusNotFound)
return fmt.Errorf("This is now implemented in the client.")
@ -365,10 +421,10 @@ func getImagesViz(eng *engine.Engine, version version.Version, w http.ResponseWr
return nil
}
func getInfo(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getInfo(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
w.Header().Set("Content-Type", "application/json")
info, err := getDaemon(eng).SystemInfo()
info, err := s.daemon.SystemInfo()
if err != nil {
return err
}
@ -376,7 +432,7 @@ func getInfo(eng *engine.Engine, version version.Version, w http.ResponseWriter,
return writeJSON(w, http.StatusOK, info)
}
func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getEvents(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -427,7 +483,7 @@ func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWrite
return true
}
d := getDaemon(eng)
d := s.daemon
es := d.EventsService
w.Header().Set("Content-Type", "application/json")
enc := json.NewEncoder(utils.NewWriteFlusher(w))
@ -480,13 +536,13 @@ func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWrite
}
}
func getImagesHistory(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getImagesHistory(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
history, err := getDaemon(eng).Repositories().History(name)
history, err := s.daemon.Repositories().History(name)
if err != nil {
return err
}
@ -494,14 +550,13 @@ func getImagesHistory(eng *engine.Engine, version version.Version, w http.Respon
return writeJSON(w, http.StatusOK, history)
}
func getContainersChanges(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getContainersChanges(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
d := getDaemon(eng)
cont, err := d.Get(name)
cont, err := s.daemon.Get(name)
if err != nil {
return err
}
@ -514,7 +569,7 @@ func getContainersChanges(eng *engine.Engine, version version.Version, w http.Re
return writeJSON(w, http.StatusOK, changes)
}
func getContainersTop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getContainersTop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if version.LessThan("1.4") {
return fmt.Errorf("top was improved a lot since 1.3, Please upgrade your docker client.")
}
@ -527,7 +582,7 @@ func getContainersTop(eng *engine.Engine, version version.Version, w http.Respon
return err
}
procList, err := getDaemon(eng).ContainerTop(vars["name"], r.Form.Get("ps_args"))
procList, err := s.daemon.ContainerTop(vars["name"], r.Form.Get("ps_args"))
if err != nil {
return err
}
@ -535,7 +590,7 @@ func getContainersTop(eng *engine.Engine, version version.Version, w http.Respon
return writeJSON(w, http.StatusOK, procList)
}
func getContainersJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getContainersJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -556,7 +611,7 @@ func getContainersJSON(eng *engine.Engine, version version.Version, w http.Respo
config.Limit = limit
}
containers, err := getDaemon(eng).Containers(config)
containers, err := s.daemon.Containers(config)
if err != nil {
return err
}
@ -564,7 +619,7 @@ func getContainersJSON(eng *engine.Engine, version version.Version, w http.Respo
return writeJSON(w, http.StatusOK, containers)
}
func getContainersStats(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getContainersStats(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -572,12 +627,10 @@ func getContainersStats(eng *engine.Engine, version version.Version, w http.Resp
return fmt.Errorf("Missing parameter")
}
d := getDaemon(eng)
return d.ContainerStats(vars["name"], utils.NewWriteFlusher(w))
return s.daemon.ContainerStats(vars["name"], utils.NewWriteFlusher(w))
}
func getContainersLogs(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getContainersLogs(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -600,15 +653,14 @@ func getContainersLogs(eng *engine.Engine, version version.Version, w http.Respo
OutStream: utils.NewWriteFlusher(w),
}
d := getDaemon(eng)
if err := d.ContainerLogs(vars["name"], logsConfig); err != nil {
if err := s.daemon.ContainerLogs(vars["name"], logsConfig); err != nil {
fmt.Fprintf(w, "Error running logs job: %s\n", err)
}
return nil
}
func postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -616,18 +668,17 @@ func postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseW
return fmt.Errorf("Missing parameter")
}
d := getDaemon(eng)
repo := r.Form.Get("repo")
tag := r.Form.Get("tag")
force := toBool(r.Form.Get("force"))
if err := d.Repositories().Tag(repo, tag, vars["name"], force); err != nil {
if err := s.daemon.Repositories().Tag(repo, tag, vars["name"], force); err != nil {
return err
}
w.WriteHeader(http.StatusCreated)
return nil
}
func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postCommit(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -653,9 +704,7 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit
Config: r.Body,
}
d := getDaemon(eng)
imgID, err := d.ContainerCommit(cont, containerCommitConfig)
imgID, err := s.daemon.ContainerCommit(cont, containerCommitConfig)
if err != nil {
return err
}
@ -666,7 +715,7 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit
}
// Creates an image from Pull or from Import
func postImagesCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postImagesCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -687,8 +736,6 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon
}
}
d := getDaemon(eng)
if image != "" { //pull
if tag == "" {
image, tag = parsers.ParseRepositoryTag(image)
@ -713,7 +760,7 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon
imagePullConfig.Json = false
}
if err := d.Repositories().Pull(image, tag, imagePullConfig, eng); err != nil {
if err := s.daemon.Repositories().Pull(image, tag, imagePullConfig, eng); err != nil {
return err
}
} else { //import
@ -734,7 +781,7 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon
imageImportConfig.Json = false
}
if err := d.Repositories().Import(src, repo, tag, imageImportConfig, eng); err != nil {
if err := s.daemon.Repositories().Import(src, repo, tag, imageImportConfig, eng); err != nil {
return err
}
@ -743,7 +790,7 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon
return nil
}
func getImagesSearch(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getImagesSearch(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -766,15 +813,14 @@ func getImagesSearch(eng *engine.Engine, version version.Version, w http.Respons
headers[k] = v
}
}
d := getDaemon(eng)
query, err := d.RegistryService.Search(r.Form.Get("term"), config, headers)
query, err := s.daemon.RegistryService.Search(r.Form.Get("term"), config, headers)
if err != nil {
return err
}
return json.NewEncoder(w).Encode(query.Results)
}
func postImagesPush(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postImagesPush(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
@ -826,7 +872,7 @@ func postImagesPush(eng *engine.Engine, version version.Version, w http.Response
return nil
}
func getImagesGet(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getImagesGet(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
@ -846,14 +892,14 @@ func getImagesGet(eng *engine.Engine, version version.Version, w http.ResponseWr
return job.Run()
}
func postImagesLoad(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postImagesLoad(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
job := eng.Job("load")
job.Stdin.Add(r.Body)
job.Stdout.Add(w)
return job.Run()
}
func postContainersCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return nil
}
@ -870,7 +916,7 @@ func postContainersCreate(eng *engine.Engine, version version.Version, w http.Re
return err
}
containerId, warnings, err := getDaemon(eng).ContainerCreate(name, config, hostConfig)
containerId, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig)
if err != nil {
return err
}
@ -881,7 +927,7 @@ func postContainersCreate(eng *engine.Engine, version version.Version, w http.Re
})
}
func postContainersRestart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersRestart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -889,13 +935,12 @@ func postContainersRestart(eng *engine.Engine, version version.Version, w http.R
return fmt.Errorf("Missing parameter")
}
s, err := strconv.Atoi(r.Form.Get("t"))
timeout, err := strconv.Atoi(r.Form.Get("t"))
if err != nil {
return err
}
d := getDaemon(eng)
if err := d.ContainerRestart(vars["name"], s); err != nil {
if err := s.daemon.ContainerRestart(vars["name"], timeout); err != nil {
return err
}
@ -904,7 +949,7 @@ func postContainersRestart(eng *engine.Engine, version version.Version, w http.R
return nil
}
func postContainerRename(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainerRename(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -912,17 +957,16 @@ func postContainerRename(eng *engine.Engine, version version.Version, w http.Res
return fmt.Errorf("Missing parameter")
}
d := getDaemon(eng)
name := vars["name"]
newName := r.Form.Get("name")
if err := d.ContainerRename(name, newName); err != nil {
if err := s.daemon.ContainerRename(name, newName); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func deleteContainers(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) deleteContainers(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -931,14 +975,13 @@ func deleteContainers(eng *engine.Engine, version version.Version, w http.Respon
}
name := vars["name"]
d := getDaemon(eng)
config := &daemon.ContainerRmConfig{
ForceRemove: toBool(r.Form.Get("force")),
RemoveVolume: toBool(r.Form.Get("v")),
RemoveLink: toBool(r.Form.Get("link")),
}
if err := d.ContainerRm(name, config); err != nil {
if err := s.daemon.ContainerRm(name, config); err != nil {
// Force a 404 for the empty string
if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") {
return fmt.Errorf("no such id: \"\"")
@ -951,7 +994,7 @@ func deleteContainers(eng *engine.Engine, version version.Version, w http.Respon
return nil
}
func deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -959,12 +1002,11 @@ func deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWr
return fmt.Errorf("Missing parameter")
}
d := getDaemon(eng)
name := vars["name"]
force := toBool(r.Form.Get("force"))
noprune := toBool(r.Form.Get("noprune"))
list, err := d.ImageDelete(name, force, noprune)
list, err := s.daemon.ImageDelete(name, force, noprune)
if err != nil {
return err
}
@ -972,7 +1014,7 @@ func deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWr
return writeJSON(w, http.StatusOK, list)
}
func postContainersStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
@ -997,7 +1039,7 @@ func postContainersStart(eng *engine.Engine, version version.Version, w http.Res
hostConfig = c
}
if err := getDaemon(eng).ContainerStart(vars["name"], hostConfig); err != nil {
if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil {
if err.Error() == "Container already started" {
w.WriteHeader(http.StatusNotModified)
return nil
@ -1008,7 +1050,7 @@ func postContainersStart(eng *engine.Engine, version version.Version, w http.Res
return nil
}
func postContainersStop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersStop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -1016,13 +1058,12 @@ func postContainersStop(eng *engine.Engine, version version.Version, w http.Resp
return fmt.Errorf("Missing parameter")
}
d := getDaemon(eng)
seconds, err := strconv.Atoi(r.Form.Get("t"))
if err != nil {
return err
}
if err := d.ContainerStop(vars["name"], seconds); err != nil {
if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil {
if err.Error() == "Container already stopped" {
w.WriteHeader(http.StatusNotModified)
return nil
@ -1034,14 +1075,13 @@ func postContainersStop(eng *engine.Engine, version version.Version, w http.Resp
return nil
}
func postContainersWait(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersWait(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
d := getDaemon(eng)
cont, err := d.Get(name)
cont, err := s.daemon.Get(name)
if err != nil {
return err
}
@ -1053,7 +1093,7 @@ func postContainersWait(eng *engine.Engine, version version.Version, w http.Resp
})
}
func postContainersResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -1070,8 +1110,7 @@ func postContainersResize(eng *engine.Engine, version version.Version, w http.Re
return err
}
d := getDaemon(eng)
cont, err := d.Get(vars["name"])
cont, err := s.daemon.Get(vars["name"])
if err != nil {
return err
}
@ -1079,7 +1118,7 @@ func postContainersResize(eng *engine.Engine, version version.Version, w http.Re
return cont.Resize(height, width)
}
func postContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -1087,9 +1126,7 @@ func postContainersAttach(eng *engine.Engine, version version.Version, w http.Re
return fmt.Errorf("Missing parameter")
}
d := getDaemon(eng)
cont, err := d.Get(vars["name"])
cont, err := s.daemon.Get(vars["name"])
if err != nil {
return err
}
@ -1136,16 +1173,14 @@ func postContainersAttach(eng *engine.Engine, version version.Version, w http.Re
return nil
}
func wsContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) wsContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
d := getDaemon(eng)
cont, err := d.Get(vars["name"])
cont, err := s.daemon.Get(vars["name"])
if err != nil {
return err
}
@ -1164,7 +1199,7 @@ func wsContainersAttach(eng *engine.Engine, version version.Version, w http.Resp
return nil
}
func getContainersByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getContainersByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
@ -1176,13 +1211,12 @@ func getContainersByName(eng *engine.Engine, version version.Version, w http.Res
return job.Run()
}
func getExecByID(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getExecByID(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter 'id'")
}
d := getDaemon(eng)
eConfig, err := d.ContainerExecInspect(vars["id"])
eConfig, err := s.daemon.ContainerExecInspect(vars["id"])
if err != nil {
return err
}
@ -1190,7 +1224,7 @@ func getExecByID(eng *engine.Engine, version version.Version, w http.ResponseWri
return writeJSON(w, http.StatusOK, eConfig)
}
func getImagesByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) getImagesByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
@ -1202,7 +1236,7 @@ func getImagesByName(eng *engine.Engine, version version.Version, w http.Respons
return job.Run()
}
func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postBuild(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if version.LessThan("1.3") {
return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.")
}
@ -1292,7 +1326,7 @@ func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWrite
return nil
}
func postContainersCopy(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainersCopy(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
@ -1316,7 +1350,7 @@ func postContainersCopy(eng *engine.Engine, version version.Version, w http.Resp
res = res[1:]
}
cont, err := getDaemon(eng).Get(vars["name"])
cont, err := s.daemon.Get(vars["name"])
if err != nil {
logrus.Errorf("%v", err)
if strings.Contains(strings.ToLower(err.Error()), "no such id") {
@ -1342,7 +1376,7 @@ func postContainersCopy(eng *engine.Engine, version version.Version, w http.Resp
return nil
}
func postContainerExecCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainerExecCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return nil
}
@ -1379,7 +1413,7 @@ func postContainerExecCreate(eng *engine.Engine, version version.Version, w http
}
// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
func postContainerExecStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainerExecStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return nil
}
@ -1430,7 +1464,7 @@ func postContainerExecStart(eng *engine.Engine, version version.Version, w http.
return nil
}
func postContainerExecResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) postContainerExecResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
@ -1447,12 +1481,10 @@ func postContainerExecResize(eng *engine.Engine, version version.Version, w http
return err
}
d := getDaemon(eng)
return d.ContainerExecResize(vars["name"], height, width)
return s.daemon.ContainerExecResize(vars["name"], height, width)
}
func optionsHandler(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) optionsHandler(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
w.WriteHeader(http.StatusOK)
return nil
}
@ -1463,7 +1495,7 @@ func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string
w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
}
func ping(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *Server) ping(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
_, err := w.Write([]byte{'O', 'K'})
return err
}
@ -1504,71 +1536,72 @@ func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, local
}
// we keep enableCors just for legacy usage, need to be removed in the future
func createRouter(eng *engine.Engine, logging, enableCors bool, corsHeaders string, dockerVersion string) *mux.Router {
func createRouter(s *Server, eng *engine.Engine) *mux.Router {
r := mux.NewRouter()
if os.Getenv("DEBUG") != "" {
ProfilerSetup(r, "/debug/")
}
m := map[string]map[string]HttpApiFunc{
"GET": {
"/_ping": ping,
"/events": getEvents,
"/info": getInfo,
"/version": getVersion,
"/images/json": getImagesJSON,
"/images/viz": getImagesViz,
"/images/search": getImagesSearch,
"/images/get": getImagesGet,
"/images/{name:.*}/get": getImagesGet,
"/images/{name:.*}/history": getImagesHistory,
"/images/{name:.*}/json": getImagesByName,
"/containers/ps": getContainersJSON,
"/containers/json": getContainersJSON,
"/containers/{name:.*}/export": getContainersExport,
"/containers/{name:.*}/changes": getContainersChanges,
"/containers/{name:.*}/json": getContainersByName,
"/containers/{name:.*}/top": getContainersTop,
"/containers/{name:.*}/logs": getContainersLogs,
"/containers/{name:.*}/stats": getContainersStats,
"/containers/{name:.*}/attach/ws": wsContainersAttach,
"/exec/{id:.*}/json": getExecByID,
"/_ping": s.ping,
"/events": s.getEvents,
"/info": s.getInfo,
"/version": s.getVersion,
"/images/json": s.getImagesJSON,
"/images/viz": s.getImagesViz,
"/images/search": s.getImagesSearch,
"/images/get": s.getImagesGet,
"/images/{name:.*}/get": s.getImagesGet,
"/images/{name:.*}/history": s.getImagesHistory,
"/images/{name:.*}/json": s.getImagesByName,
"/containers/ps": s.getContainersJSON,
"/containers/json": s.getContainersJSON,
"/containers/{name:.*}/export": s.getContainersExport,
"/containers/{name:.*}/changes": s.getContainersChanges,
"/containers/{name:.*}/json": s.getContainersByName,
"/containers/{name:.*}/top": s.getContainersTop,
"/containers/{name:.*}/logs": s.getContainersLogs,
"/containers/{name:.*}/stats": s.getContainersStats,
"/containers/{name:.*}/attach/ws": s.wsContainersAttach,
"/exec/{id:.*}/json": s.getExecByID,
},
"POST": {
"/auth": postAuth,
"/commit": postCommit,
"/build": postBuild,
"/images/create": postImagesCreate,
"/images/load": postImagesLoad,
"/images/{name:.*}/push": postImagesPush,
"/images/{name:.*}/tag": postImagesTag,
"/containers/create": postContainersCreate,
"/containers/{name:.*}/kill": postContainersKill,
"/containers/{name:.*}/pause": postContainersPause,
"/containers/{name:.*}/unpause": postContainersUnpause,
"/containers/{name:.*}/restart": postContainersRestart,
"/containers/{name:.*}/start": postContainersStart,
"/containers/{name:.*}/stop": postContainersStop,
"/containers/{name:.*}/wait": postContainersWait,
"/containers/{name:.*}/resize": postContainersResize,
"/containers/{name:.*}/attach": postContainersAttach,
"/containers/{name:.*}/copy": postContainersCopy,
"/containers/{name:.*}/exec": postContainerExecCreate,
"/exec/{name:.*}/start": postContainerExecStart,
"/exec/{name:.*}/resize": postContainerExecResize,
"/containers/{name:.*}/rename": postContainerRename,
"/auth": s.postAuth,
"/commit": s.postCommit,
"/build": s.postBuild,
"/images/create": s.postImagesCreate,
"/images/load": s.postImagesLoad,
"/images/{name:.*}/push": s.postImagesPush,
"/images/{name:.*}/tag": s.postImagesTag,
"/containers/create": s.postContainersCreate,
"/containers/{name:.*}/kill": s.postContainersKill,
"/containers/{name:.*}/pause": s.postContainersPause,
"/containers/{name:.*}/unpause": s.postContainersUnpause,
"/containers/{name:.*}/restart": s.postContainersRestart,
"/containers/{name:.*}/start": s.postContainersStart,
"/containers/{name:.*}/stop": s.postContainersStop,
"/containers/{name:.*}/wait": s.postContainersWait,
"/containers/{name:.*}/resize": s.postContainersResize,
"/containers/{name:.*}/attach": s.postContainersAttach,
"/containers/{name:.*}/copy": s.postContainersCopy,
"/containers/{name:.*}/exec": s.postContainerExecCreate,
"/exec/{name:.*}/start": s.postContainerExecStart,
"/exec/{name:.*}/resize": s.postContainerExecResize,
"/containers/{name:.*}/rename": s.postContainerRename,
},
"DELETE": {
"/containers/{name:.*}": deleteContainers,
"/images/{name:.*}": deleteImages,
"/containers/{name:.*}": s.deleteContainers,
"/images/{name:.*}": s.deleteImages,
},
"OPTIONS": {
"": optionsHandler,
"": s.optionsHandler,
},
}
// If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*"
// otherwise, all head values will be passed to HTTP handler
if corsHeaders == "" && enableCors {
corsHeaders := s.cfg.CorsHeaders
if corsHeaders == "" && s.cfg.EnableCors {
corsHeaders = "*"
}
@ -1581,7 +1614,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, corsHeaders stri
localMethod := method
// build the handler function
f := makeHttpHandler(eng, logging, localMethod, localRoute, localFct, corsHeaders, version.Version(dockerVersion))
f := makeHttpHandler(eng, s.cfg.Logging, localMethod, localRoute, localFct, corsHeaders, version.Version(s.cfg.Version))
// add the new route
if localRoute == "" {
@ -1600,7 +1633,14 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, corsHeaders stri
// FIXME: refactor this to be part of Server and not require re-creating a new
// router each time. This requires first moving ListenAndServe into Server.
func ServeRequest(eng *engine.Engine, apiversion version.Version, w http.ResponseWriter, req *http.Request) {
router := createRouter(eng, false, true, "", "")
cfg := &ServerConfig{
EnableCors: true,
Version: string(apiversion),
}
api := New(cfg, eng)
daemon, _ := eng.HackGetGlobalVar("httpapi.daemon").(*daemon.Daemon)
api.AcceptConnections(daemon)
router := createRouter(api, eng)
// Insert APIVERSION into the request as a convenience
req.URL.Path = fmt.Sprintf("/v%s%s", apiversion, req.URL.Path)
router.ServeHTTP(w, req)
@ -1632,50 +1672,6 @@ func allocateDaemonPort(addr string) error {
return nil
}
type Server interface {
Serve() error
Close() error
}
// ServeApi loops through all of the protocols sent in to docker and spawns
// off a go routine to setup a serving http.Server for each.
func ServeApi(protoAddrs []string, conf *ServerConfig, eng *engine.Engine) error {
var chErrors = make(chan error, len(protoAddrs))
for _, protoAddr := range protoAddrs {
protoAddrParts := strings.SplitN(protoAddr, "://", 2)
if len(protoAddrParts) != 2 {
return fmt.Errorf("bad format, expected PROTO://ADDR")
}
go func() {
logrus.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
srv, err := NewServer(protoAddrParts[0], protoAddrParts[1], conf, eng)
if err != nil {
chErrors <- err
return
}
eng.OnShutdown(func() {
if err := srv.Close(); err != nil {
logrus.Error(err)
}
})
if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
err = nil
}
chErrors <- err
}()
}
for i := 0; i < len(protoAddrs); i++ {
err := <-chErrors
if err != nil {
return err
}
}
return nil
}
func toBool(s string) bool {
s = strings.ToLower(strings.TrimSpace(s))
return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")

View file

@ -8,22 +8,15 @@ import (
"net/http"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/engine"
"github.com/docker/docker/daemon"
"github.com/docker/docker/pkg/systemd"
)
// NewServer sets up the required Server and does protocol specific checking.
func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Server, error) {
// newServer sets up the required serverCloser and does protocol specific checking.
func (s *Server) newServer(proto, addr string) (serverCloser, error) {
var (
err error
l net.Listener
r = createRouter(
eng,
conf.Logging,
conf.EnableCors,
conf.CorsHeaders,
conf.Version,
)
)
switch proto {
case "fd":
@ -35,13 +28,13 @@ func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Serv
// We don't want to start serving on these sockets until the
// daemon is initialized and installed. Otherwise required handlers
// won't be ready.
<-activationLock
<-s.start
// Since ListenFD will return one or more sockets we have
// to create a go func to spawn off multiple serves
for i := range ls {
listener := ls[i]
go func() {
httpSrv := http.Server{Handler: r}
httpSrv := http.Server{Handler: s.router}
chErrors <- httpSrv.Serve(listener)
}()
}
@ -52,17 +45,17 @@ func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Serv
}
return nil, nil
case "tcp":
if !conf.TlsVerify {
if !s.cfg.TlsVerify {
logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
}
if l, err = NewTcpSocket(addr, tlsConfigFromServerConfig(conf)); err != nil {
if l, err = NewTcpSocket(addr, tlsConfigFromServerConfig(s.cfg), s.start); err != nil {
return nil, err
}
if err := allocateDaemonPort(addr); err != nil {
return nil, err
}
case "unix":
if l, err = NewUnixSocket(addr, conf.SocketGroup); err != nil {
if l, err = NewUnixSocket(addr, s.cfg.SocketGroup, s.start); err != nil {
return nil, err
}
default:
@ -71,19 +64,20 @@ func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Serv
return &HttpServer{
&http.Server{
Addr: addr,
Handler: r,
Handler: s.router,
},
l,
}, nil
}
func AcceptConnections() {
func (s *Server) AcceptConnections(d *daemon.Daemon) {
// Tell the init daemon we are accepting requests
s.daemon = d
go systemd.SdNotify("READY=1")
// close the lock so the listeners start accepting connections
select {
case <-activationLock:
case <-s.start:
default:
close(activationLock)
close(s.start)
}
}

View file

@ -5,30 +5,24 @@ package server
import (
"errors"
"net"
"net/http"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/engine"
"github.com/docker/docker/daemon"
)
// NewServer sets up the required Server and does protocol specific checking.
func NewServer(proto, addr string, job *engine.Job) (Server, error) {
func (s *Server) newServer(proto, addr string) (Server, error) {
var (
err error
l net.Listener
r = createRouter(
job.Eng,
job.GetenvBool("Logging"),
job.GetenvBool("EnableCors"),
job.Getenv("CorsHeaders"),
job.Getenv("Version"),
)
)
switch proto {
case "tcp":
if !job.GetenvBool("TlsVerify") {
if !s.cfg.TlsVerify {
logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
}
if l, err = NewTcpSocket(addr, tlsConfigFromJob(job)); err != nil {
if l, err = NewTcpSocket(addr, tlsConfigFromServerConfig(s.cfg)); err != nil {
return nil, err
}
if err := allocateDaemonPort(addr); err != nil {
@ -37,13 +31,21 @@ func NewServer(proto, addr string, job *engine.Job) (Server, error) {
default:
return nil, errors.New("Invalid protocol format. Windows only supports tcp.")
}
return &HttpServer{
&http.Server{
Addr: addr,
Handler: s.router,
},
l,
}, nil
}
func AcceptConnections() {
func (s *Server) AcceptConnections(d *daemon.Daemon) {
s.daemon = d
// close the lock so the listeners start accepting connections
select {
case <-activationLock:
case <-s.start:
default:
close(activationLock)
close(s.start)
}
}

View file

@ -31,8 +31,8 @@ func tlsConfigFromServerConfig(conf *ServerConfig) *tlsConfig {
}
}
func NewTcpSocket(addr string, config *tlsConfig) (net.Listener, error) {
l, err := listenbuffer.NewListenBuffer("tcp", addr, activationLock)
func NewTcpSocket(addr string, config *tlsConfig, activate <-chan struct{}) (net.Listener, error) {
l, err := listenbuffer.NewListenBuffer("tcp", addr, activate)
if err != nil {
return nil, err
}

View file

@ -12,13 +12,13 @@ import (
"github.com/docker/libcontainer/user"
)
func NewUnixSocket(path, group string) (net.Listener, error) {
func NewUnixSocket(path, group string, activate <-chan struct{}) (net.Listener, error) {
if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
return nil, err
}
mask := syscall.Umask(0777)
defer syscall.Umask(mask)
l, err := listenbuffer.NewListenBuffer("unix", path, activationLock)
l, err := listenbuffer.NewListenBuffer("unix", path, activate)
if err != nil {
return nil, err
}

View file

@ -7,7 +7,6 @@ import (
"io"
"os"
"path/filepath"
"strings"
"github.com/Sirupsen/logrus"
apiserver "github.com/docker/docker/api/server"
@ -93,40 +92,6 @@ func mainDaemon() {
}
daemonCfg.TrustKeyPath = *flTrustKey
registryService := registry.NewService(registryCfg)
// load the daemon in the background so we can immediately start
// the http api so that connections don't fail while the daemon
// is booting
daemonInitWait := make(chan error)
go func() {
d, err := daemon.NewDaemon(daemonCfg, eng, registryService)
if err != nil {
daemonInitWait <- err
return
}
logrus.WithFields(logrus.Fields{
"version": dockerversion.VERSION,
"commit": dockerversion.GITCOMMIT,
"execdriver": d.ExecutionDriver().Name(),
"graphdriver": d.GraphDriver().String(),
}).Info("Docker daemon")
if err := d.Install(eng); err != nil {
daemonInitWait <- err
return
}
b := &builder.BuilderJob{eng, d}
b.Install()
// after the daemon is done setting up we can tell the api to start
// accepting connections
apiserver.AcceptConnections()
daemonInitWait <- nil
}()
serverConfig := &apiserver.ServerConfig{
Logging: true,
EnableCors: daemonCfg.EnableCors,
@ -140,12 +105,14 @@ func mainDaemon() {
TlsKey: *flKey,
}
api := apiserver.New(serverConfig, eng)
// 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 := apiserver.ServeApi(flHosts, serverConfig, eng); err != nil {
if err := api.ServeApi(flHosts); err != nil {
logrus.Errorf("ServeAPI error: %v", err)
serveAPIWait <- err
return
@ -153,30 +120,37 @@ func mainDaemon() {
serveAPIWait <- nil
}()
// Wait for the daemon startup goroutine to finish
// This makes sure we can actually cleanly shutdown the daemon
logrus.Debug("waiting for daemon to initialize")
errDaemon := <-daemonInitWait
if errDaemon != nil {
registryService := registry.NewService(registryCfg)
d, err := daemon.NewDaemon(daemonCfg, eng, registryService)
if err != nil {
eng.Shutdown()
outStr := fmt.Sprintf("Shutting down daemon due to errors: %v", errDaemon)
if strings.Contains(errDaemon.Error(), "engine is shutdown") {
// if the error is "engine is shutdown", we've already reported (or
// will report below in API server errors) the error
outStr = "Shutting down daemon due to reported errors"
}
// we must "fatal" exit here as the API server may be happy to
// continue listening forever if the error had no impact to API
logrus.Fatal(outStr)
} else {
logrus.Info("Daemon has completed initialization")
logrus.Fatalf("Error starting daemon: %v", err)
}
if err := d.Install(eng); err != nil {
eng.Shutdown()
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")
b := &builder.BuilderJob{eng, d}
b.Install()
// 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 job to complete
errAPI := <-serveAPIWait
// If we have an error here it is unique to API (as daemonErr would have
// exited the daemon process above)
eng.Shutdown()
if errAPI != nil {
logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI)

View file

@ -498,9 +498,9 @@ func TestDaemonExitOnFailure(t *testing.T) {
t.Fatalf("Expected daemon not to start, got %v", err)
}
// look in the log and make sure we got the message that daemon is shutting down
runCmd := exec.Command("grep", "Shutting down daemon due to", d.LogfileName())
runCmd := exec.Command("grep", "Error starting daemon", d.LogfileName())
if out, _, err := runCommandWithOutput(runCmd); err != nil {
t.Fatalf("Expected 'shutting down daemon due to error' message; but doesn't exist in log: %q, err: %v", out, err)
t.Fatalf("Expected 'Error starting daemon' message; but doesn't exist in log: %q, err: %v", out, err)
}
} else {
//if we didn't get an error and the daemon is running, this is a failure

View file

@ -48,9 +48,7 @@ const (
)
var (
// FIXME: globalDaemon is deprecated by globalEngine. All tests should be converted.
globalDaemon *daemon.Daemon
globalEngine *engine.Engine
globalHttpsEngine *engine.Engine
globalRogueHttpsEngine *engine.Engine
startFds int
@ -153,9 +151,10 @@ func spawnGlobalDaemon() {
}
t := std_log.New(os.Stderr, "", 0)
eng := NewTestEngine(t)
globalEngine = eng
globalDaemon = mkDaemonFromEngine(eng, t)
serverConfig := &apiserver.ServerConfig{Logging: true}
api := apiserver.New(serverConfig, eng)
// Spawn a Daemon
go func() {
logrus.Debugf("Spawning global daemon for integration tests")
@ -164,8 +163,7 @@ func spawnGlobalDaemon() {
Host: testDaemonAddr,
}
serverConfig := &apiserver.ServerConfig{Logging: true}
if err := apiserver.ServeApi([]string{listenURL.String()}, serverConfig, eng); err != nil {
if err := api.ServeApi([]string{listenURL.String()}); err != nil {
logrus.Fatalf("Unable to spawn the test daemon: %s", err)
}
}()
@ -174,7 +172,7 @@ func spawnGlobalDaemon() {
// FIXME: use inmem transports instead of tcp
time.Sleep(time.Second)
apiserver.AcceptConnections()
api.AcceptConnections(getDaemon(eng))
}
func spawnLegitHttpsDaemon() {
@ -204,6 +202,15 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine {
eng := newTestEngine(t, true, root)
serverConfig := &apiserver.ServerConfig{
Logging: true,
Tls: true,
TlsVerify: true,
TlsCa: cacert,
TlsCert: cert,
TlsKey: key,
}
api := apiserver.New(serverConfig, eng)
// Spawn a Daemon
go func() {
logrus.Debugf("Spawning https daemon for integration tests")
@ -211,15 +218,7 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine {
Scheme: testDaemonHttpsProto,
Host: addr,
}
serverConfig := &apiserver.ServerConfig{
Logging: true,
Tls: true,
TlsVerify: true,
TlsCa: cacert,
TlsCert: cert,
TlsKey: key,
}
if err := apiserver.ServeApi([]string{listenURL.String()}, serverConfig, eng); err != nil {
if err := api.ServeApi([]string{listenURL.String()}); err != nil {
logrus.Fatalf("Unable to spawn the test daemon: %s", err)
}
}()
@ -227,7 +226,7 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine {
// Give some time to ListenAndServer to actually start
time.Sleep(time.Second)
apiserver.AcceptConnections()
api.AcceptConnections(getDaemon(eng))
return eng
}

View file

@ -32,7 +32,7 @@ import "net"
// NewListenBuffer returns a net.Listener listening on addr with the protocol
// passed. The channel passed is used to activate the listenbuffer when the
// caller is ready to accept connections.
func NewListenBuffer(proto, addr string, activate chan struct{}) (net.Listener, error) {
func NewListenBuffer(proto, addr string, activate <-chan struct{}) (net.Listener, error) {
wrapped, err := net.Listen(proto, addr)
if err != nil {
return nil, err
@ -46,9 +46,9 @@ func NewListenBuffer(proto, addr string, activate chan struct{}) (net.Listener,
// defaultListener is the buffered wrapper around the net.Listener
type defaultListener struct {
wrapped net.Listener // The net.Listener wrapped by listenbuffer
ready bool // Whether the listenbuffer has been activated
activate chan struct{} // Channel to control activation of the listenbuffer
wrapped net.Listener // The net.Listener wrapped by listenbuffer
ready bool // Whether the listenbuffer has been activated
activate <-chan struct{} // Channel to control activation of the listenbuffer
}
// Close closes the wrapped socket.