Browse code

Make API server datastructure

Added daemon field to it, will use it later for acces to daemon from
handlers

Signed-off-by: Alexander Morozov <lk4d4@docker.com>

Alexander Morozov authored on 2015/04/18 06:32:18
Showing 8 changed files
... ...
@@ -40,10 +40,6 @@ import (
40 40
 	"github.com/docker/docker/utils"
41 41
 )
42 42
 
43
-var (
44
-	activationLock = make(chan struct{})
45
-)
46
-
47 43
 type ServerConfig struct {
48 44
 	Logging     bool
49 45
 	EnableCors  bool
... ...
@@ -57,6 +53,80 @@ type ServerConfig struct {
57 57
 	TlsKey      string
58 58
 }
59 59
 
60
+type Server struct {
61
+	daemon *daemon.Daemon
62
+	cfg    *ServerConfig
63
+	router *mux.Router
64
+	start  chan struct{}
65
+
66
+	// TODO: delete engine
67
+	eng *engine.Engine
68
+}
69
+
70
+func New(cfg *ServerConfig, eng *engine.Engine) *Server {
71
+	r := createRouter(
72
+		eng,
73
+		cfg.Logging,
74
+		cfg.EnableCors,
75
+		cfg.CorsHeaders,
76
+		cfg.Version,
77
+	)
78
+	return &Server{
79
+		cfg:    cfg,
80
+		router: r,
81
+		start:  make(chan struct{}),
82
+		eng:    eng,
83
+	}
84
+}
85
+
86
+func (s *Server) SetDaemon(d *daemon.Daemon) {
87
+	s.daemon = d
88
+}
89
+
90
+type serverCloser interface {
91
+	Serve() error
92
+	Close() error
93
+}
94
+
95
+// ServeApi loops through all of the protocols sent in to docker and spawns
96
+// off a go routine to setup a serving http.Server for each.
97
+func (s *Server) ServeApi(protoAddrs []string) error {
98
+	var chErrors = make(chan error, len(protoAddrs))
99
+
100
+	for _, protoAddr := range protoAddrs {
101
+		protoAddrParts := strings.SplitN(protoAddr, "://", 2)
102
+		if len(protoAddrParts) != 2 {
103
+			return fmt.Errorf("bad format, expected PROTO://ADDR")
104
+		}
105
+		go func(proto, addr string) {
106
+			logrus.Infof("Listening for HTTP on %s (%s)", proto, addr)
107
+			srv, err := s.newServer(proto, addr)
108
+			if err != nil {
109
+				chErrors <- err
110
+				return
111
+			}
112
+			s.eng.OnShutdown(func() {
113
+				if err := srv.Close(); err != nil {
114
+					logrus.Error(err)
115
+				}
116
+			})
117
+			if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
118
+				err = nil
119
+			}
120
+			chErrors <- err
121
+		}(protoAddrParts[0], protoAddrParts[1])
122
+	}
123
+
124
+	for i := 0; i < len(protoAddrs); i++ {
125
+		err := <-chErrors
126
+		if err != nil {
127
+			return err
128
+		}
129
+	}
130
+
131
+	return nil
132
+}
133
+
60 134
 type HttpServer struct {
61 135
 	srv *http.Server
62 136
 	l   net.Listener
... ...
@@ -1632,50 +1702,6 @@ func allocateDaemonPort(addr string) error {
1632 1632
 	return nil
1633 1633
 }
1634 1634
 
1635
-type Server interface {
1636
-	Serve() error
1637
-	Close() error
1638
-}
1639
-
1640
-// ServeApi loops through all of the protocols sent in to docker and spawns
1641
-// off a go routine to setup a serving http.Server for each.
1642
-func ServeApi(protoAddrs []string, conf *ServerConfig, eng *engine.Engine) error {
1643
-	var chErrors = make(chan error, len(protoAddrs))
1644
-
1645
-	for _, protoAddr := range protoAddrs {
1646
-		protoAddrParts := strings.SplitN(protoAddr, "://", 2)
1647
-		if len(protoAddrParts) != 2 {
1648
-			return fmt.Errorf("bad format, expected PROTO://ADDR")
1649
-		}
1650
-		go func() {
1651
-			logrus.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
1652
-			srv, err := NewServer(protoAddrParts[0], protoAddrParts[1], conf, eng)
1653
-			if err != nil {
1654
-				chErrors <- err
1655
-				return
1656
-			}
1657
-			eng.OnShutdown(func() {
1658
-				if err := srv.Close(); err != nil {
1659
-					logrus.Error(err)
1660
-				}
1661
-			})
1662
-			if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
1663
-				err = nil
1664
-			}
1665
-			chErrors <- err
1666
-		}()
1667
-	}
1668
-
1669
-	for i := 0; i < len(protoAddrs); i++ {
1670
-		err := <-chErrors
1671
-		if err != nil {
1672
-			return err
1673
-		}
1674
-	}
1675
-
1676
-	return nil
1677
-}
1678
-
1679 1635
 func toBool(s string) bool {
1680 1636
 	s = strings.ToLower(strings.TrimSpace(s))
1681 1637
 	return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
... ...
@@ -8,22 +8,15 @@ import (
8 8
 	"net/http"
9 9
 
10 10
 	"github.com/Sirupsen/logrus"
11
-	"github.com/docker/docker/engine"
11
+	"github.com/docker/docker/daemon"
12 12
 	"github.com/docker/docker/pkg/systemd"
13 13
 )
14 14
 
15
-// NewServer sets up the required Server and does protocol specific checking.
16
-func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Server, error) {
15
+// newServer sets up the required serverCloser and does protocol specific checking.
16
+func (s *Server) newServer(proto, addr string) (serverCloser, error) {
17 17
 	var (
18 18
 		err error
19 19
 		l   net.Listener
20
-		r   = createRouter(
21
-			eng,
22
-			conf.Logging,
23
-			conf.EnableCors,
24
-			conf.CorsHeaders,
25
-			conf.Version,
26
-		)
27 20
 	)
28 21
 	switch proto {
29 22
 	case "fd":
... ...
@@ -35,13 +28,13 @@ func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Serv
35 35
 		// We don't want to start serving on these sockets until the
36 36
 		// daemon is initialized and installed. Otherwise required handlers
37 37
 		// won't be ready.
38
-		<-activationLock
38
+		<-s.start
39 39
 		// Since ListenFD will return one or more sockets we have
40 40
 		// to create a go func to spawn off multiple serves
41 41
 		for i := range ls {
42 42
 			listener := ls[i]
43 43
 			go func() {
44
-				httpSrv := http.Server{Handler: r}
44
+				httpSrv := http.Server{Handler: s.router}
45 45
 				chErrors <- httpSrv.Serve(listener)
46 46
 			}()
47 47
 		}
... ...
@@ -52,17 +45,17 @@ func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Serv
52 52
 		}
53 53
 		return nil, nil
54 54
 	case "tcp":
55
-		if !conf.TlsVerify {
55
+		if !s.cfg.TlsVerify {
56 56
 			logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
57 57
 		}
58
-		if l, err = NewTcpSocket(addr, tlsConfigFromServerConfig(conf)); err != nil {
58
+		if l, err = NewTcpSocket(addr, tlsConfigFromServerConfig(s.cfg), s.start); err != nil {
59 59
 			return nil, err
60 60
 		}
61 61
 		if err := allocateDaemonPort(addr); err != nil {
62 62
 			return nil, err
63 63
 		}
64 64
 	case "unix":
65
-		if l, err = NewUnixSocket(addr, conf.SocketGroup); err != nil {
65
+		if l, err = NewUnixSocket(addr, s.cfg.SocketGroup, s.start); err != nil {
66 66
 			return nil, err
67 67
 		}
68 68
 	default:
... ...
@@ -71,19 +64,20 @@ func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Serv
71 71
 	return &HttpServer{
72 72
 		&http.Server{
73 73
 			Addr:    addr,
74
-			Handler: r,
74
+			Handler: s.router,
75 75
 		},
76 76
 		l,
77 77
 	}, nil
78 78
 }
79 79
 
80
-func AcceptConnections() {
80
+func (s *Server) AcceptConnections(d *daemon.Daemon) {
81 81
 	// Tell the init daemon we are accepting requests
82
+	s.daemon = d
82 83
 	go systemd.SdNotify("READY=1")
83 84
 	// close the lock so the listeners start accepting connections
84 85
 	select {
85
-	case <-activationLock:
86
+	case <-s.start:
86 87
 	default:
87
-		close(activationLock)
88
+		close(s.start)
88 89
 	}
89 90
 }
... ...
@@ -5,30 +5,24 @@ package server
5 5
 import (
6 6
 	"errors"
7 7
 	"net"
8
+	"net/http"
8 9
 
9 10
 	"github.com/Sirupsen/logrus"
10
-	"github.com/docker/docker/engine"
11
+	"github.com/docker/docker/daemon"
11 12
 )
12 13
 
13 14
 // NewServer sets up the required Server and does protocol specific checking.
14
-func NewServer(proto, addr string, job *engine.Job) (Server, error) {
15
+func (s *Server) newServer(proto, addr string) (Server, error) {
15 16
 	var (
16 17
 		err error
17 18
 		l   net.Listener
18
-		r   = createRouter(
19
-			job.Eng,
20
-			job.GetenvBool("Logging"),
21
-			job.GetenvBool("EnableCors"),
22
-			job.Getenv("CorsHeaders"),
23
-			job.Getenv("Version"),
24
-		)
25 19
 	)
26 20
 	switch proto {
27 21
 	case "tcp":
28
-		if !job.GetenvBool("TlsVerify") {
22
+		if !s.cfg.TlsVerify {
29 23
 			logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
30 24
 		}
31
-		if l, err = NewTcpSocket(addr, tlsConfigFromJob(job)); err != nil {
25
+		if l, err = NewTcpSocket(addr, tlsConfigFromServerConfig(s.cfg)); err != nil {
32 26
 			return nil, err
33 27
 		}
34 28
 		if err := allocateDaemonPort(addr); err != nil {
... ...
@@ -37,13 +31,21 @@ func NewServer(proto, addr string, job *engine.Job) (Server, error) {
37 37
 	default:
38 38
 		return nil, errors.New("Invalid protocol format. Windows only supports tcp.")
39 39
 	}
40
+	return &HttpServer{
41
+		&http.Server{
42
+			Addr:    addr,
43
+			Handler: s.router,
44
+		},
45
+		l,
46
+	}, nil
40 47
 }
41 48
 
42
-func AcceptConnections() {
49
+func (s *Server) AcceptConnections(d *daemon.Daemon) {
50
+	s.daemon = d
43 51
 	// close the lock so the listeners start accepting connections
44 52
 	select {
45
-	case <-activationLock:
53
+	case <-s.start:
46 54
 	default:
47
-		close(activationLock)
55
+		close(s.start)
48 56
 	}
49 57
 }
... ...
@@ -31,8 +31,8 @@ func tlsConfigFromServerConfig(conf *ServerConfig) *tlsConfig {
31 31
 	}
32 32
 }
33 33
 
34
-func NewTcpSocket(addr string, config *tlsConfig) (net.Listener, error) {
35
-	l, err := listenbuffer.NewListenBuffer("tcp", addr, activationLock)
34
+func NewTcpSocket(addr string, config *tlsConfig, activate <-chan struct{}) (net.Listener, error) {
35
+	l, err := listenbuffer.NewListenBuffer("tcp", addr, activate)
36 36
 	if err != nil {
37 37
 		return nil, err
38 38
 	}
... ...
@@ -12,13 +12,13 @@ import (
12 12
 	"github.com/docker/libcontainer/user"
13 13
 )
14 14
 
15
-func NewUnixSocket(path, group string) (net.Listener, error) {
15
+func NewUnixSocket(path, group string, activate <-chan struct{}) (net.Listener, error) {
16 16
 	if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
17 17
 		return nil, err
18 18
 	}
19 19
 	mask := syscall.Umask(0777)
20 20
 	defer syscall.Umask(mask)
21
-	l, err := listenbuffer.NewListenBuffer("unix", path, activationLock)
21
+	l, err := listenbuffer.NewListenBuffer("unix", path, activate)
22 22
 	if err != nil {
23 23
 		return nil, err
24 24
 	}
... ...
@@ -105,12 +105,14 @@ func mainDaemon() {
105 105
 		TlsKey:      *flKey,
106 106
 	}
107 107
 
108
+	api := apiserver.New(serverConfig, eng)
109
+
108 110
 	// The serve API routine never exits unless an error occurs
109 111
 	// We need to start it as a goroutine and wait on it so
110 112
 	// daemon doesn't exit
111 113
 	serveAPIWait := make(chan error)
112 114
 	go func() {
113
-		if err := apiserver.ServeApi(flHosts, serverConfig, eng); err != nil {
115
+		if err := api.ServeApi(flHosts); err != nil {
114 116
 			logrus.Errorf("ServeAPI error: %v", err)
115 117
 			serveAPIWait <- err
116 118
 			return
... ...
@@ -143,8 +145,8 @@ func mainDaemon() {
143 143
 	b.Install()
144 144
 
145 145
 	// after the daemon is done setting up we can tell the api to start
146
-	// accepting connections
147
-	apiserver.AcceptConnections()
146
+	// accepting connections with specified daemon
147
+	api.AcceptConnections(d)
148 148
 
149 149
 	// Daemon is fully initialized and handling API traffic
150 150
 	// Wait for serve API job to complete
... ...
@@ -156,6 +156,8 @@ func spawnGlobalDaemon() {
156 156
 	globalEngine = eng
157 157
 	globalDaemon = mkDaemonFromEngine(eng, t)
158 158
 
159
+	serverConfig := &apiserver.ServerConfig{Logging: true}
160
+	api := apiserver.New(serverConfig, eng)
159 161
 	// Spawn a Daemon
160 162
 	go func() {
161 163
 		logrus.Debugf("Spawning global daemon for integration tests")
... ...
@@ -164,8 +166,7 @@ func spawnGlobalDaemon() {
164 164
 			Host:   testDaemonAddr,
165 165
 		}
166 166
 
167
-		serverConfig := &apiserver.ServerConfig{Logging: true}
168
-		if err := apiserver.ServeApi([]string{listenURL.String()}, serverConfig, eng); err != nil {
167
+		if err := api.ServeApi([]string{listenURL.String()}); err != nil {
169 168
 			logrus.Fatalf("Unable to spawn the test daemon: %s", err)
170 169
 		}
171 170
 	}()
... ...
@@ -174,7 +175,7 @@ func spawnGlobalDaemon() {
174 174
 	// FIXME: use inmem transports instead of tcp
175 175
 	time.Sleep(time.Second)
176 176
 
177
-	apiserver.AcceptConnections()
177
+	api.AcceptConnections(getDaemon(eng))
178 178
 }
179 179
 
180 180
 func spawnLegitHttpsDaemon() {
... ...
@@ -204,6 +205,15 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine {
204 204
 
205 205
 	eng := newTestEngine(t, true, root)
206 206
 
207
+	serverConfig := &apiserver.ServerConfig{
208
+		Logging:   true,
209
+		Tls:       true,
210
+		TlsVerify: true,
211
+		TlsCa:     cacert,
212
+		TlsCert:   cert,
213
+		TlsKey:    key,
214
+	}
215
+	api := apiserver.New(serverConfig, eng)
207 216
 	// Spawn a Daemon
208 217
 	go func() {
209 218
 		logrus.Debugf("Spawning https daemon for integration tests")
... ...
@@ -211,15 +221,7 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine {
211 211
 			Scheme: testDaemonHttpsProto,
212 212
 			Host:   addr,
213 213
 		}
214
-		serverConfig := &apiserver.ServerConfig{
215
-			Logging:   true,
216
-			Tls:       true,
217
-			TlsVerify: true,
218
-			TlsCa:     cacert,
219
-			TlsCert:   cert,
220
-			TlsKey:    key,
221
-		}
222
-		if err := apiserver.ServeApi([]string{listenURL.String()}, serverConfig, eng); err != nil {
214
+		if err := api.ServeApi([]string{listenURL.String()}); err != nil {
223 215
 			logrus.Fatalf("Unable to spawn the test daemon: %s", err)
224 216
 		}
225 217
 	}()
... ...
@@ -227,7 +229,7 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine {
227 227
 	// Give some time to ListenAndServer to actually start
228 228
 	time.Sleep(time.Second)
229 229
 
230
-	apiserver.AcceptConnections()
230
+	api.AcceptConnections(getDaemon(eng))
231 231
 
232 232
 	return eng
233 233
 }
... ...
@@ -32,7 +32,7 @@ import "net"
32 32
 // NewListenBuffer returns a net.Listener listening on addr with the protocol
33 33
 // passed. The channel passed is used to activate the listenbuffer when the
34 34
 // caller is ready to accept connections.
35
-func NewListenBuffer(proto, addr string, activate chan struct{}) (net.Listener, error) {
35
+func NewListenBuffer(proto, addr string, activate <-chan struct{}) (net.Listener, error) {
36 36
 	wrapped, err := net.Listen(proto, addr)
37 37
 	if err != nil {
38 38
 		return nil, err
... ...
@@ -46,9 +46,9 @@ func NewListenBuffer(proto, addr string, activate chan struct{}) (net.Listener,
46 46
 
47 47
 // defaultListener is the buffered wrapper around the net.Listener
48 48
 type defaultListener struct {
49
-	wrapped  net.Listener  // The net.Listener wrapped by listenbuffer
50
-	ready    bool          // Whether the listenbuffer has been activated
51
-	activate chan struct{} // Channel to control activation of the listenbuffer
49
+	wrapped  net.Listener    // The net.Listener wrapped by listenbuffer
50
+	ready    bool            // Whether the listenbuffer has been activated
51
+	activate <-chan struct{} // Channel to control activation of the listenbuffer
52 52
 }
53 53
 
54 54
 // Close closes the wrapped socket.