github.com/ncdc/docker@v0.10.1-0.20160129113957-6c6729ef5b74/api/server/server.go (about)

     1  package server
     2  
     3  import (
     4  	"crypto/tls"
     5  	"net"
     6  	"net/http"
     7  	"strings"
     8  
     9  	"github.com/Sirupsen/logrus"
    10  	"github.com/docker/docker/api/server/httputils"
    11  	"github.com/docker/docker/api/server/router"
    12  	"github.com/docker/docker/api/server/router/build"
    13  	"github.com/docker/docker/api/server/router/container"
    14  	"github.com/docker/docker/api/server/router/local"
    15  	"github.com/docker/docker/api/server/router/network"
    16  	"github.com/docker/docker/api/server/router/system"
    17  	"github.com/docker/docker/api/server/router/volume"
    18  	"github.com/docker/docker/daemon"
    19  	"github.com/docker/docker/pkg/authorization"
    20  	"github.com/docker/docker/utils"
    21  	"github.com/docker/go-connections/sockets"
    22  	"github.com/gorilla/mux"
    23  	"golang.org/x/net/context"
    24  )
    25  
    26  // versionMatcher defines a variable matcher to be parsed by the router
    27  // when a request is about to be served.
    28  const versionMatcher = "/v{version:[0-9.]+}"
    29  
    30  // Config provides the configuration for the API server
    31  type Config struct {
    32  	Logging                  bool
    33  	EnableCors               bool
    34  	CorsHeaders              string
    35  	AuthorizationPluginNames []string
    36  	Version                  string
    37  	SocketGroup              string
    38  	TLSConfig                *tls.Config
    39  	Addrs                    []Addr
    40  }
    41  
    42  // Server contains instance details for the server
    43  type Server struct {
    44  	cfg           *Config
    45  	servers       []*HTTPServer
    46  	routers       []router.Router
    47  	authZPlugins  []authorization.Plugin
    48  	routerSwapper *routerSwapper
    49  }
    50  
    51  // Addr contains string representation of address and its protocol (tcp, unix...).
    52  type Addr struct {
    53  	Proto string
    54  	Addr  string
    55  }
    56  
    57  // New returns a new instance of the server based on the specified configuration.
    58  // It allocates resources which will be needed for ServeAPI(ports, unix-sockets).
    59  func New(cfg *Config) (*Server, error) {
    60  	s := &Server{
    61  		cfg: cfg,
    62  	}
    63  	for _, addr := range cfg.Addrs {
    64  		srv, err := s.newServer(addr.Proto, addr.Addr)
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  		logrus.Debugf("Server created for HTTP on %s (%s)", addr.Proto, addr.Addr)
    69  		s.servers = append(s.servers, srv...)
    70  	}
    71  	return s, nil
    72  }
    73  
    74  // Close closes servers and thus stop receiving requests
    75  func (s *Server) Close() {
    76  	for _, srv := range s.servers {
    77  		if err := srv.Close(); err != nil {
    78  			logrus.Error(err)
    79  		}
    80  	}
    81  }
    82  
    83  // serveAPI loops through all initialized servers and spawns goroutine
    84  // with Server method for each. It sets createMux() as Handler also.
    85  func (s *Server) serveAPI() error {
    86  	s.initRouterSwapper()
    87  
    88  	var chErrors = make(chan error, len(s.servers))
    89  	for _, srv := range s.servers {
    90  		srv.srv.Handler = s.routerSwapper
    91  		go func(srv *HTTPServer) {
    92  			var err error
    93  			logrus.Infof("API listen on %s", srv.l.Addr())
    94  			if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
    95  				err = nil
    96  			}
    97  			chErrors <- err
    98  		}(srv)
    99  	}
   100  
   101  	for i := 0; i < len(s.servers); i++ {
   102  		err := <-chErrors
   103  		if err != nil {
   104  			return err
   105  		}
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  // HTTPServer contains an instance of http server and the listener.
   112  // srv *http.Server, contains configuration to create a http server and a mux router with all api end points.
   113  // l   net.Listener, is a TCP or Socket listener that dispatches incoming request to the router.
   114  type HTTPServer struct {
   115  	srv *http.Server
   116  	l   net.Listener
   117  }
   118  
   119  // Serve starts listening for inbound requests.
   120  func (s *HTTPServer) Serve() error {
   121  	return s.srv.Serve(s.l)
   122  }
   123  
   124  // Close closes the HTTPServer from listening for the inbound requests.
   125  func (s *HTTPServer) Close() error {
   126  	return s.l.Close()
   127  }
   128  
   129  func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string) {
   130  	logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
   131  	w.Header().Add("Access-Control-Allow-Origin", corsHeaders)
   132  	w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
   133  	w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
   134  }
   135  
   136  func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) {
   137  	if s.cfg.TLSConfig == nil || s.cfg.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert {
   138  		logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
   139  	}
   140  	if l, err = sockets.NewTCPSocket(addr, s.cfg.TLSConfig); err != nil {
   141  		return nil, err
   142  	}
   143  	if err := allocateDaemonPort(addr); err != nil {
   144  		return nil, err
   145  	}
   146  	return
   147  }
   148  
   149  func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
   150  	return func(w http.ResponseWriter, r *http.Request) {
   151  		// log the handler call
   152  		logrus.Debugf("Calling %s %s", r.Method, r.URL.Path)
   153  
   154  		// Define the context that we'll pass around to share info
   155  		// like the docker-request-id.
   156  		//
   157  		// The 'context' will be used for global data that should
   158  		// apply to all requests. Data that is specific to the
   159  		// immediate function being called should still be passed
   160  		// as 'args' on the function call.
   161  		ctx := context.Background()
   162  		handlerFunc := s.handleWithGlobalMiddlewares(handler)
   163  
   164  		vars := mux.Vars(r)
   165  		if vars == nil {
   166  			vars = make(map[string]string)
   167  		}
   168  
   169  		if err := handlerFunc(ctx, w, r, vars); err != nil {
   170  			logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.URL.Path, utils.GetErrorMessage(err))
   171  			httputils.WriteError(w, err)
   172  		}
   173  	}
   174  }
   175  
   176  // InitRouters initializes a list of routers for the server.
   177  func (s *Server) InitRouters(d *daemon.Daemon) {
   178  	s.addRouter(container.NewRouter(d))
   179  	s.addRouter(local.NewRouter(d))
   180  	s.addRouter(network.NewRouter(d))
   181  	s.addRouter(system.NewRouter(d))
   182  	s.addRouter(volume.NewRouter(d))
   183  	s.addRouter(build.NewRouter(d))
   184  }
   185  
   186  // addRouter adds a new router to the server.
   187  func (s *Server) addRouter(r router.Router) {
   188  	s.routers = append(s.routers, r)
   189  }
   190  
   191  // createMux initializes the main router the server uses.
   192  func (s *Server) createMux() *mux.Router {
   193  	m := mux.NewRouter()
   194  	if utils.IsDebugEnabled() {
   195  		profilerSetup(m, "/debug/")
   196  	}
   197  
   198  	logrus.Debugf("Registering routers")
   199  	for _, apiRouter := range s.routers {
   200  		for _, r := range apiRouter.Routes() {
   201  			f := s.makeHTTPHandler(r.Handler())
   202  
   203  			logrus.Debugf("Registering %s, %s", r.Method(), r.Path())
   204  			m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f)
   205  			m.Path(r.Path()).Methods(r.Method()).Handler(f)
   206  		}
   207  	}
   208  
   209  	return m
   210  }
   211  
   212  // Wait blocks the server goroutine until it exits.
   213  // It sends an error message if there is any error during
   214  // the API execution.
   215  func (s *Server) Wait(waitChan chan error) {
   216  	if err := s.serveAPI(); err != nil {
   217  		logrus.Errorf("ServeAPI error: %v", err)
   218  		waitChan <- err
   219  		return
   220  	}
   221  	waitChan <- nil
   222  }
   223  
   224  func (s *Server) initRouterSwapper() {
   225  	s.routerSwapper = &routerSwapper{
   226  		router: s.createMux(),
   227  	}
   228  }
   229  
   230  // Reload reads configuration changes and modifies the
   231  // server according to those changes.
   232  // Currently, only the --debug configuration is taken into account.
   233  func (s *Server) Reload(config *daemon.Config) {
   234  	debugEnabled := utils.IsDebugEnabled()
   235  	switch {
   236  	case debugEnabled && !config.Debug: // disable debug
   237  		utils.DisableDebug()
   238  		s.routerSwapper.Swap(s.createMux())
   239  	case config.Debug && !debugEnabled: // enable debug
   240  		utils.EnableDebug()
   241  		s.routerSwapper.Swap(s.createMux())
   242  	}
   243  }