Browse code

Merge pull request #9031 from cpuguy83/cleanup_api_server_creation

Cleanup api server creation

Alexandr Morozov authored on 2014/11/13 08:37:34
Showing 1 changed files
... ...
@@ -3,8 +3,7 @@ package server
3 3
 import (
4 4
 	"bufio"
5 5
 	"bytes"
6
-	"crypto/tls"
7
-	"crypto/x509"
6
+
8 7
 	"encoding/base64"
9 8
 	"encoding/json"
10 9
 	"expvar"
... ...
@@ -19,6 +18,9 @@ import (
19 19
 	"strings"
20 20
 	"syscall"
21 21
 
22
+	"crypto/tls"
23
+	"crypto/x509"
24
+
22 25
 	"code.google.com/p/go.net/websocket"
23 26
 	"github.com/docker/libcontainer/user"
24 27
 	"github.com/gorilla/mux"
... ...
@@ -39,6 +41,18 @@ var (
39 39
 	activationLock chan struct{}
40 40
 )
41 41
 
42
+type HttpServer struct {
43
+	srv *http.Server
44
+	l   net.Listener
45
+}
46
+
47
+func (s *HttpServer) Serve() error {
48
+	return s.srv.Serve(s.l)
49
+}
50
+func (s *HttpServer) Close() error {
51
+	return s.l.Close()
52
+}
53
+
42 54
 type HttpApiFunc func(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error
43 55
 
44 56
 func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
... ...
@@ -1334,9 +1348,14 @@ func ServeRequest(eng *engine.Engine, apiversion version.Version, w http.Respons
1334 1334
 	return nil
1335 1335
 }
1336 1336
 
1337
-// ServeFD creates an http.Server and sets it up to serve given a socket activated
1337
+// serveFd creates an http.Server and sets it up to serve given a socket activated
1338 1338
 // argument.
1339
-func ServeFd(addr string, handle http.Handler) error {
1339
+func serveFd(addr string, job *engine.Job) error {
1340
+	r, err := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version"))
1341
+	if err != nil {
1342
+		return err
1343
+	}
1344
+
1340 1345
 	ls, e := systemd.ListenFD(addr)
1341 1346
 	if e != nil {
1342 1347
 		return e
... ...
@@ -1354,7 +1373,7 @@ func ServeFd(addr string, handle http.Handler) error {
1354 1354
 	for i := range ls {
1355 1355
 		listener := ls[i]
1356 1356
 		go func() {
1357
-			httpSrv := http.Server{Handler: handle}
1357
+			httpSrv := http.Server{Handler: r}
1358 1358
 			chErrors <- httpSrv.Serve(listener)
1359 1359
 		}()
1360 1360
 	}
... ...
@@ -1386,6 +1405,41 @@ func lookupGidByName(nameOrGid string) (int, error) {
1386 1386
 	return -1, fmt.Errorf("Group %s not found", nameOrGid)
1387 1387
 }
1388 1388
 
1389
+func setupTls(cert, key, ca string, l net.Listener) (net.Listener, error) {
1390
+	tlsCert, err := tls.LoadX509KeyPair(cert, key)
1391
+	if err != nil {
1392
+		return nil, fmt.Errorf("Couldn't load X509 key pair (%s, %s): %s. Key encrypted?",
1393
+			cert, key, err)
1394
+	}
1395
+	tlsConfig := &tls.Config{
1396
+		NextProtos:   []string{"http/1.1"},
1397
+		Certificates: []tls.Certificate{tlsCert},
1398
+		// Avoid fallback on insecure SSL protocols
1399
+		MinVersion: tls.VersionTLS10,
1400
+	}
1401
+
1402
+	if ca != "" {
1403
+		certPool := x509.NewCertPool()
1404
+		file, err := ioutil.ReadFile(ca)
1405
+		if err != nil {
1406
+			return nil, fmt.Errorf("Couldn't read CA certificate: %s", err)
1407
+		}
1408
+		certPool.AppendCertsFromPEM(file)
1409
+		tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
1410
+		tlsConfig.ClientCAs = certPool
1411
+	}
1412
+
1413
+	return tls.NewListener(l, tlsConfig), nil
1414
+}
1415
+
1416
+func newListener(proto, addr string, bufferRequests bool) (net.Listener, error) {
1417
+	if bufferRequests {
1418
+		return listenbuffer.NewListenBuffer(proto, addr, activationLock)
1419
+	}
1420
+
1421
+	return net.Listen(proto, addr)
1422
+}
1423
+
1389 1424
 func changeGroup(addr string, nameOrGid string) error {
1390 1425
 	gid, err := lookupGidByName(nameOrGid)
1391 1426
 	if err != nil {
... ...
@@ -1396,99 +1450,95 @@ func changeGroup(addr string, nameOrGid string) error {
1396 1396
 	return os.Chown(addr, 0, gid)
1397 1397
 }
1398 1398
 
1399
-// ListenAndServe sets up the required http.Server and gets it listening for
1400
-// each addr passed in and does protocol specific checking.
1401
-func ListenAndServe(proto, addr string, job *engine.Job) error {
1402
-	var l net.Listener
1399
+func setSocketGroup(addr, group string) error {
1400
+	if group == "" {
1401
+		return nil
1402
+	}
1403
+
1404
+	if err := changeGroup(addr, group); err != nil {
1405
+		if group != "docker" {
1406
+			return err
1407
+		}
1408
+		log.Debugf("Warning: could not chgrp %s to docker: %v", addr, err)
1409
+	}
1410
+
1411
+	return nil
1412
+}
1413
+
1414
+func setupUnixHttp(addr string, job *engine.Job) (*HttpServer, error) {
1403 1415
 	r, err := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version"))
1404 1416
 	if err != nil {
1405
-		return err
1417
+		return nil, err
1406 1418
 	}
1407 1419
 
1408
-	if proto == "fd" {
1409
-		return ServeFd(addr, r)
1420
+	if err := syscall.Unlink(addr); err != nil && !os.IsNotExist(err) {
1421
+		return nil, err
1410 1422
 	}
1423
+	mask := syscall.Umask(0777)
1424
+	defer syscall.Umask(mask)
1411 1425
 
1412
-	if proto == "unix" {
1413
-		if err := syscall.Unlink(addr); err != nil && !os.IsNotExist(err) {
1414
-			return err
1415
-		}
1426
+	l, err := newListener("unix", addr, job.GetenvBool("BufferRequests"))
1427
+	if err != nil {
1428
+		return nil, err
1416 1429
 	}
1417 1430
 
1418
-	var oldmask int
1419
-	if proto == "unix" {
1420
-		oldmask = syscall.Umask(0777)
1431
+	if err := setSocketGroup(addr, job.Getenv("SocketGroup")); err != nil {
1432
+		return nil, err
1421 1433
 	}
1422 1434
 
1423
-	if job.GetenvBool("BufferRequests") {
1424
-		l, err = listenbuffer.NewListenBuffer(proto, addr, activationLock)
1425
-	} else {
1426
-		l, err = net.Listen(proto, addr)
1435
+	if err := os.Chmod(addr, 0660); err != nil {
1436
+		return nil, err
1427 1437
 	}
1428 1438
 
1429
-	if proto == "unix" {
1430
-		syscall.Umask(oldmask)
1439
+	return &HttpServer{&http.Server{Addr: addr, Handler: r}, l}, nil
1440
+}
1441
+
1442
+func setupTcpHttp(addr string, job *engine.Job) (*HttpServer, error) {
1443
+	if !strings.HasPrefix(addr, "127.0.0.1") && !job.GetenvBool("TlsVerify") {
1444
+		log.Infof("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
1431 1445
 	}
1446
+
1447
+	r, err := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version"))
1432 1448
 	if err != nil {
1433
-		return err
1449
+		return nil, err
1434 1450
 	}
1435 1451
 
1436
-	if proto != "unix" && (job.GetenvBool("Tls") || job.GetenvBool("TlsVerify")) {
1437
-		tlsCert := job.Getenv("TlsCert")
1438
-		tlsKey := job.Getenv("TlsKey")
1439
-		cert, err := tls.LoadX509KeyPair(tlsCert, tlsKey)
1440
-		if err != nil {
1441
-			return fmt.Errorf("Couldn't load X509 key pair (%s, %s): %s. Key encrypted?",
1442
-				tlsCert, tlsKey, err)
1443
-		}
1444
-		tlsConfig := &tls.Config{
1445
-			NextProtos:   []string{"http/1.1"},
1446
-			Certificates: []tls.Certificate{cert},
1447
-			// Avoid fallback on insecure SSL protocols
1448
-			MinVersion: tls.VersionTLS10,
1449
-		}
1450
-		if job.GetenvBool("TlsVerify") {
1451
-			certPool := x509.NewCertPool()
1452
-			file, err := ioutil.ReadFile(job.Getenv("TlsCa"))
1453
-			if err != nil {
1454
-				return fmt.Errorf("Couldn't read CA certificate: %s", err)
1455
-			}
1456
-			certPool.AppendCertsFromPEM(file)
1452
+	l, err := newListener("tcp", addr, job.GetenvBool("BufferRequests"))
1453
+	if err != nil {
1454
+		return nil, err
1455
+	}
1457 1456
 
1458
-			tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
1459
-			tlsConfig.ClientCAs = certPool
1457
+	if job.GetenvBool("Tls") || job.GetenvBool("TlsVerify") {
1458
+		var tlsCa string
1459
+		if job.GetenvBool("TlsVerify") {
1460
+			tlsCa = job.Getenv("TlsCa")
1461
+		}
1462
+		l, err = setupTls(job.Getenv("TlsCert"), job.Getenv("TlsKey"), tlsCa, l)
1463
+		if err != nil {
1464
+			return nil, err
1460 1465
 		}
1461
-		l = tls.NewListener(l, tlsConfig)
1462 1466
 	}
1467
+	return &HttpServer{&http.Server{Addr: addr, Handler: r}, l}, nil
1468
+}
1463 1469
 
1470
+// NewServer sets up the required Server and does protocol specific checking.
1471
+func NewServer(proto, addr string, job *engine.Job) (Server, error) {
1464 1472
 	// Basic error and sanity checking
1465 1473
 	switch proto {
1474
+	case "fd":
1475
+		return nil, serveFd(addr, job)
1466 1476
 	case "tcp":
1467
-		if !strings.HasPrefix(addr, "127.0.0.1") && !job.GetenvBool("TlsVerify") {
1468
-			log.Infof("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
1469
-		}
1477
+		return setupTcpHttp(addr, job)
1470 1478
 	case "unix":
1471
-		socketGroup := job.Getenv("SocketGroup")
1472
-		if socketGroup != "" {
1473
-			if err := changeGroup(addr, socketGroup); err != nil {
1474
-				if socketGroup == "docker" {
1475
-					// if the user hasn't explicitly specified the group ownership, don't fail on errors.
1476
-					log.Debugf("Warning: could not chgrp %s to docker: %s", addr, err.Error())
1477
-				} else {
1478
-					return err
1479
-				}
1480
-			}
1481
-
1482
-		}
1483
-		if err := os.Chmod(addr, 0660); err != nil {
1484
-			return err
1485
-		}
1479
+		return setupUnixHttp(addr, job)
1486 1480
 	default:
1487
-		return fmt.Errorf("Invalid protocol format.")
1481
+		return nil, fmt.Errorf("Invalid protocol format.")
1488 1482
 	}
1483
+}
1489 1484
 
1490
-	httpSrv := http.Server{Addr: addr, Handler: r}
1491
-	return httpSrv.Serve(l)
1485
+type Server interface {
1486
+	Serve() error
1487
+	Close() error
1492 1488
 }
1493 1489
 
1494 1490
 // ServeApi loops through all of the protocols sent in to docker and spawns
... ...
@@ -1510,7 +1560,12 @@ func ServeApi(job *engine.Job) engine.Status {
1510 1510
 		}
1511 1511
 		go func() {
1512 1512
 			log.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
1513
-			chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], job)
1513
+			srv, err := NewServer(protoAddrParts[0], protoAddrParts[1], job)
1514
+			if err != nil {
1515
+				chErrors <- err
1516
+				return
1517
+			}
1518
+			chErrors <- srv.Serve()
1514 1519
 		}()
1515 1520
 	}
1516 1521