Merge lp:~pedronis/ubuntu-push/server-lego into lp:ubuntu-push
- server-lego
- Merge into trunk
Proposed by
Samuele Pedroni
Status: | Merged |
---|---|
Approved by: | Samuele Pedroni |
Approved revision: | 18 |
Merged at revision: | 17 |
Proposed branch: | lp:~pedronis/ubuntu-push/server-lego |
Merge into: | lp:ubuntu-push |
Prerequisite: | lp:~pedronis/ubuntu-push/server-lego-preps |
Diff against target: |
654 lines (+290/-212) 7 files modified
server/dev/bootlog.go (+35/-0) server/dev/bootlog_test.go (+45/-0) server/dev/config_test.go (+27/-61) server/dev/runner_devices.go (+67/-69) server/dev/runner_http.go (+22/-12) server/dev/runner_test.go (+73/-27) server/dev/server.go (+21/-43) |
To merge this branch: | bzr merge lp:~pedronis/ubuntu-push/server-lego |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
John Lenton (community) | Approve | ||
Review via email: mp+202628@code.launchpad.net |
Commit message
make server/dev into composable pieces, somewhat big mostly because of lots of shuffling around
Description of the change
make server/dev into composable pieces, somewhat big mostly because of lots of shuffling around
probably still needs some moving around in a subsequent branch
To post a comment you must log in.
Revision history for this message
John Lenton (chipaca) wrote : | # |
Revision history for this message
John Lenton (chipaca) : | # |
review:
Disapprove
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'server/dev/bootlog.go' |
2 | --- server/dev/bootlog.go 1970-01-01 00:00:00 +0000 |
3 | +++ server/dev/bootlog.go 2014-01-22 09:51:22 +0000 |
4 | @@ -0,0 +1,35 @@ |
5 | +/* |
6 | + Copyright 2013-2014 Canonical Ltd. |
7 | + |
8 | + This program is free software: you can redistribute it and/or modify it |
9 | + under the terms of the GNU General Public License version 3, as published |
10 | + by the Free Software Foundation. |
11 | + |
12 | + This program is distributed in the hope that it will be useful, but |
13 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
14 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
15 | + PURPOSE. See the GNU General Public License for more details. |
16 | + |
17 | + You should have received a copy of the GNU General Public License along |
18 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | +*/ |
20 | + |
21 | +package main |
22 | + |
23 | +import ( |
24 | + "launchpad.net/ubuntu-push/logger" |
25 | + "net" |
26 | + "os" |
27 | +) |
28 | + |
29 | +// boot logging and hooks |
30 | + |
31 | +func bootLogListener(kind string, lst net.Listener) { |
32 | + BootLogger.Infof("listening for %s on %v", kind, lst.Addr()) |
33 | +} |
34 | + |
35 | +var ( |
36 | + BootLogger = logger.NewSimpleLogger(os.Stderr, "debug") |
37 | + BootLogListener = bootLogListener |
38 | + BootLogFatalf = BootLogger.Fatalf |
39 | +) |
40 | |
41 | === added file 'server/dev/bootlog_test.go' |
42 | --- server/dev/bootlog_test.go 1970-01-01 00:00:00 +0000 |
43 | +++ server/dev/bootlog_test.go 2014-01-22 09:51:22 +0000 |
44 | @@ -0,0 +1,45 @@ |
45 | +/* |
46 | + Copyright 2013-2014 Canonical Ltd. |
47 | + |
48 | + This program is free software: you can redistribute it and/or modify it |
49 | + under the terms of the GNU General Public License version 3, as published |
50 | + by the Free Software Foundation. |
51 | + |
52 | + This program is distributed in the hope that it will be useful, but |
53 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
54 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
55 | + PURPOSE. See the GNU General Public License for more details. |
56 | + |
57 | + You should have received a copy of the GNU General Public License along |
58 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
59 | +*/ |
60 | + |
61 | +package main |
62 | + |
63 | +import ( |
64 | + "bytes" |
65 | + . "launchpad.net/gocheck" |
66 | + "launchpad.net/ubuntu-push/logger" |
67 | + "net" |
68 | + "testing" |
69 | +) |
70 | + |
71 | +func TestRunners(t *testing.T) { TestingT(t) } |
72 | + |
73 | +type bootlogSuite struct{} |
74 | + |
75 | +var _ = Suite(&bootlogSuite{}) |
76 | + |
77 | +func (s *bootlogSuite) TestBootLogListener(c *C) { |
78 | + buf := &bytes.Buffer{} |
79 | + prevBootLogger := BootLogger |
80 | + BootLogger = logger.NewSimpleLogger(buf, "info") |
81 | + defer func() { |
82 | + BootLogger = prevBootLogger |
83 | + }() |
84 | + lst, err := net.Listen("tcp", "127.0.0.1:0") |
85 | + c.Assert(err, IsNil) |
86 | + defer lst.Close() |
87 | + BootLogListener("client", lst) |
88 | + c.Check(buf.String(), Matches, ".* INFO listening for client on "+lst.Addr().String()+"\n") |
89 | +} |
90 | |
91 | === renamed file 'server/dev/server_test.go' => 'server/dev/config_test.go' |
92 | --- server/dev/server_test.go 2014-01-14 15:35:20 +0000 |
93 | +++ server/dev/config_test.go 2014-01-22 09:51:22 +0000 |
94 | @@ -17,28 +17,20 @@ |
95 | package main |
96 | |
97 | import ( |
98 | - // "fmt" |
99 | "bytes" |
100 | "io/ioutil" |
101 | . "launchpad.net/gocheck" |
102 | + "launchpad.net/ubuntu-push/config" |
103 | "os" |
104 | "path/filepath" |
105 | - "testing" |
106 | "time" |
107 | ) |
108 | |
109 | -func TestDevserver(t *testing.T) { TestingT(t) } |
110 | - |
111 | -type devserverSuite struct{} |
112 | - |
113 | -var _ = Suite(&devserverSuite{}) |
114 | - |
115 | -func (s *devserverSuite) TestConfigRead(c *C) { |
116 | - tmpDir := c.MkDir() |
117 | - err := ioutil.WriteFile(filepath.Join(tmpDir, "key.key"), []byte("KeY"), os.ModePerm) |
118 | - c.Assert(err, IsNil) |
119 | - err = ioutil.WriteFile(filepath.Join(tmpDir, "cert.cert"), []byte("CeRt"), os.ModePerm) |
120 | - c.Assert(err, IsNil) |
121 | +type configSuite struct{} |
122 | + |
123 | +var _ = Suite(&configSuite{}) |
124 | + |
125 | +func (s *configSuite) TestDevicesParsedConfig(c *C) { |
126 | buf := bytes.NewBufferString(`{ |
127 | "ping_interval": "5m", |
128 | "exchange_timeout": "10s", |
129 | @@ -46,60 +38,34 @@ |
130 | "broker_queue_size": 100, |
131 | "addr": "127.0.0.1:9999", |
132 | "key_pem_file": "key.key", |
133 | -"cert_pem_file": "cert.cert", |
134 | -"http_addr": "127.0.0.1:8080", |
135 | -"http_read_timeout": "5s", |
136 | -"http_write_timeout": "10s" |
137 | +"cert_pem_file": "cert.cert" |
138 | }`) |
139 | - cfg := &configuration{} |
140 | - err = cfg.read(buf, tmpDir) |
141 | + cfg := &DevicesParsedConfig{} |
142 | + err := config.ReadConfig(buf, cfg) |
143 | c.Assert(err, IsNil) |
144 | c.Check(cfg.PingInterval(), Equals, 5*time.Minute) |
145 | c.Check(cfg.ExchangeTimeout(), Equals, 10*time.Second) |
146 | c.Check(cfg.BrokerQueueSize(), Equals, uint(100)) |
147 | c.Check(cfg.SessionQueueSize(), Equals, uint(10)) |
148 | c.Check(cfg.Addr(), Equals, "127.0.0.1:9999") |
149 | +} |
150 | + |
151 | +func (s *configSuite) TestDevicesParsedConfigLoadFinish(c *C) { |
152 | + tmpDir := c.MkDir() |
153 | + cfg := &DevicesParsedConfig{ |
154 | + ParsedKeyPEMFile: "key.key", |
155 | + ParsedCertPEMFile: "cert.cert", |
156 | + } |
157 | + err := cfg.FinishLoad(tmpDir) |
158 | + c.Check(err, ErrorMatches, "reading key_pem_file:.*no such file.*") |
159 | + err = ioutil.WriteFile(filepath.Join(tmpDir, "key.key"), []byte("KeY"), os.ModePerm) |
160 | + c.Assert(err, IsNil) |
161 | + err = cfg.FinishLoad(tmpDir) |
162 | + c.Check(err, ErrorMatches, "reading cert_pem_file:.*no such file.*") |
163 | + err = ioutil.WriteFile(filepath.Join(tmpDir, "cert.cert"), []byte("CeRt"), os.ModePerm) |
164 | + c.Assert(err, IsNil) |
165 | + err = cfg.FinishLoad(tmpDir) |
166 | + c.Assert(err, IsNil) |
167 | c.Check(string(cfg.KeyPEMBlock()), Equals, "KeY") |
168 | c.Check(string(cfg.CertPEMBlock()), Equals, "CeRt") |
169 | - c.Check(cfg.HTTPAddr(), Equals, "127.0.0.1:8080") |
170 | - c.Check(cfg.HTTPReadTimeout(), Equals, 5*time.Second) |
171 | - c.Check(cfg.HTTPWriteTimeout(), Equals, 10*time.Second) |
172 | -} |
173 | - |
174 | -func (s *devserverSuite) TestConfigReadErrors(c *C) { |
175 | - tmpDir := c.MkDir() |
176 | - checkError := func(config, expectedErr string) { |
177 | - cfg := &configuration{} |
178 | - err := cfg.read(bytes.NewBufferString(config), tmpDir) |
179 | - c.Check(err, ErrorMatches, expectedErr) |
180 | - } |
181 | - checkError("", "EOF") |
182 | - checkError(`{"ping_interval": "1m"}`, "missing exchange_timeout") |
183 | - checkError(`{"ping_interval": "1m", "exchange_timeout": "5s", "session_queue_size": "foo"}`, "session_queue_size:.*type uint") |
184 | - checkError(`{ |
185 | -"exchange_timeout": "10s", |
186 | -"ping_interval": "5m", |
187 | -"broker_queue_size": 100, |
188 | -"session_queue_size": 10, |
189 | -"addr": ":9000", |
190 | -"key_pem_file": "doesntexist", |
191 | -"cert_pem_file": "doesntexist", |
192 | -"http_addr": ":8080", |
193 | -"http_read_timeout": "5s", |
194 | -"http_write_timeout": "10s" |
195 | -}`, "reading key_pem_file:.*no such file.*") |
196 | - err := ioutil.WriteFile(filepath.Join(tmpDir, "key.key"), []byte("KeY"), os.ModePerm) |
197 | - c.Assert(err, IsNil) |
198 | - checkError(`{ |
199 | -"exchange_timeout": "10s", |
200 | -"ping_interval": "5m", |
201 | -"broker_queue_size": 100, |
202 | -"session_queue_size": 10, |
203 | -"addr": ":9000", |
204 | -"key_pem_file": "key.key", |
205 | -"cert_pem_file": "doesntexist", |
206 | -"http_addr": ":8080", |
207 | -"http_read_timeout": "5s", |
208 | -"http_write_timeout": "10s" |
209 | -}`, "reading cert_pem_file:.*no such file.*") |
210 | } |
211 | |
212 | === renamed file 'server/dev/config.go' => 'server/dev/runner_devices.go' |
213 | --- server/dev/config.go 2014-01-14 15:35:20 +0000 |
214 | +++ server/dev/runner_devices.go 2014-01-22 09:51:22 +0000 |
215 | @@ -18,89 +18,37 @@ |
216 | |
217 | import ( |
218 | "fmt" |
219 | - "io" |
220 | "launchpad.net/ubuntu-push/config" |
221 | + "launchpad.net/ubuntu-push/logger" |
222 | + "launchpad.net/ubuntu-push/server/listener" |
223 | + "net" |
224 | + "syscall" |
225 | "time" |
226 | ) |
227 | |
228 | -// expectedConfiguration is used as target for JSON parsing the configuration. |
229 | -type expectedConfiguration struct { |
230 | +// A DevicesParsedConfig holds and can be used to parse the device server config. |
231 | +type DevicesParsedConfig struct { |
232 | // session configuration |
233 | - PingInterval config.ConfigTimeDuration `json:"ping_interval"` |
234 | - ExchangeTimeout config.ConfigTimeDuration `json:"exchange_timeout"` |
235 | + ParsedPingInterval config.ConfigTimeDuration `json:"ping_interval"` |
236 | + ParsedExchangeTimeout config.ConfigTimeDuration `json:"exchange_timeout"` |
237 | // broker configuration |
238 | - SessionQueueSize config.ConfigQueueSize `json:"session_queue_size"` |
239 | - BrokerQueueSize config.ConfigQueueSize `json:"broker_queue_size"` |
240 | + ParsedSessionQueueSize config.ConfigQueueSize `json:"session_queue_size"` |
241 | + ParsedBrokerQueueSize config.ConfigQueueSize `json:"broker_queue_size"` |
242 | // device listener configuration |
243 | - Addr config.ConfigHostPort `json:"addr"` |
244 | - KeyPEMFile string `json:"key_pem_file"` |
245 | - CertPEMFile string `json:"cert_pem_file"` |
246 | - // api http server configuration |
247 | - HTTPAddr config.ConfigHostPort `json:"http_addr"` |
248 | - HTTPReadTimeout config.ConfigTimeDuration `json:"http_read_timeout"` |
249 | - HTTPWriteTimeout config.ConfigTimeDuration `json:"http_write_timeout"` |
250 | -} |
251 | - |
252 | -// configuration holds the server configuration and gives it access |
253 | -// through the various component config interfaces. |
254 | -type configuration struct { |
255 | - parsed expectedConfiguration |
256 | + ParsedAddr config.ConfigHostPort `json:"addr"` |
257 | + ParsedKeyPEMFile string `json:"key_pem_file"` |
258 | + ParsedCertPEMFile string `json:"cert_pem_file"` |
259 | + // private post-processed config |
260 | certPEMBlock []byte |
261 | keyPEMBlock []byte |
262 | } |
263 | |
264 | -func (cfg *configuration) PingInterval() time.Duration { |
265 | - return cfg.parsed.PingInterval.TimeDuration() |
266 | -} |
267 | - |
268 | -func (cfg *configuration) ExchangeTimeout() time.Duration { |
269 | - return cfg.parsed.ExchangeTimeout.TimeDuration() |
270 | -} |
271 | - |
272 | -func (cfg *configuration) SessionQueueSize() uint { |
273 | - return cfg.parsed.SessionQueueSize.QueueSize() |
274 | -} |
275 | - |
276 | -func (cfg *configuration) BrokerQueueSize() uint { |
277 | - return cfg.parsed.BrokerQueueSize.QueueSize() |
278 | -} |
279 | - |
280 | -func (cfg *configuration) Addr() string { |
281 | - return cfg.parsed.Addr.HostPort() |
282 | -} |
283 | - |
284 | -func (cfg *configuration) KeyPEMBlock() []byte { |
285 | - return cfg.keyPEMBlock |
286 | -} |
287 | - |
288 | -func (cfg *configuration) CertPEMBlock() []byte { |
289 | - return cfg.certPEMBlock |
290 | -} |
291 | - |
292 | -func (cfg *configuration) HTTPAddr() string { |
293 | - return cfg.parsed.HTTPAddr.HostPort() |
294 | -} |
295 | - |
296 | -func (cfg *configuration) HTTPReadTimeout() time.Duration { |
297 | - return cfg.parsed.HTTPReadTimeout.TimeDuration() |
298 | -} |
299 | - |
300 | -func (cfg *configuration) HTTPWriteTimeout() time.Duration { |
301 | - return cfg.parsed.HTTPWriteTimeout.TimeDuration() |
302 | -} |
303 | - |
304 | -// read reads & parses configuration from the reader. it uses baseDir |
305 | -// to load mentioned files in the configuration. |
306 | -func (cfg *configuration) read(r io.Reader, baseDir string) error { |
307 | - err := config.ReadConfig(r, &cfg.parsed) |
308 | - if err != nil { |
309 | - return err |
310 | - } |
311 | - keyPEMBlock, err := config.LoadFile(cfg.parsed.KeyPEMFile, baseDir) |
312 | +func (cfg *DevicesParsedConfig) FinishLoad(baseDir string) error { |
313 | + keyPEMBlock, err := config.LoadFile(cfg.ParsedKeyPEMFile, baseDir) |
314 | if err != nil { |
315 | return fmt.Errorf("reading key_pem_file: %v", err) |
316 | } |
317 | - certPEMBlock, err := config.LoadFile(cfg.parsed.CertPEMFile, baseDir) |
318 | + certPEMBlock, err := config.LoadFile(cfg.ParsedCertPEMFile, baseDir) |
319 | if err != nil { |
320 | return fmt.Errorf("reading cert_pem_file: %v", err) |
321 | } |
322 | @@ -108,3 +56,53 @@ |
323 | cfg.certPEMBlock = certPEMBlock |
324 | return nil |
325 | } |
326 | + |
327 | +func (cfg *DevicesParsedConfig) PingInterval() time.Duration { |
328 | + return cfg.ParsedPingInterval.TimeDuration() |
329 | +} |
330 | + |
331 | +func (cfg *DevicesParsedConfig) ExchangeTimeout() time.Duration { |
332 | + return cfg.ParsedExchangeTimeout.TimeDuration() |
333 | +} |
334 | + |
335 | +func (cfg *DevicesParsedConfig) SessionQueueSize() uint { |
336 | + return cfg.ParsedSessionQueueSize.QueueSize() |
337 | +} |
338 | + |
339 | +func (cfg *DevicesParsedConfig) BrokerQueueSize() uint { |
340 | + return cfg.ParsedBrokerQueueSize.QueueSize() |
341 | +} |
342 | + |
343 | +func (cfg *DevicesParsedConfig) Addr() string { |
344 | + return cfg.ParsedAddr.HostPort() |
345 | +} |
346 | + |
347 | +func (cfg *DevicesParsedConfig) KeyPEMBlock() []byte { |
348 | + return cfg.keyPEMBlock |
349 | +} |
350 | + |
351 | +func (cfg *DevicesParsedConfig) CertPEMBlock() []byte { |
352 | + return cfg.certPEMBlock |
353 | +} |
354 | + |
355 | +// RunDevices listens for device connections. |
356 | +func DevicesRunner(session func(net.Conn) error, logger logger.Logger, parsedCfg *DevicesParsedConfig) func() { |
357 | + BootLogger.Debugf("PingInterval: %s, ExchangeTimeout %s", parsedCfg.PingInterval(), parsedCfg.ExchangeTimeout()) |
358 | + var rlim syscall.Rlimit |
359 | + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim) |
360 | + if err != nil { |
361 | + BootLogFatalf("getrlimit failed: %v", err) |
362 | + } |
363 | + BootLogger.Debugf("nofile soft: %d hard: %d", rlim.Cur, rlim.Max) |
364 | + lst, err := listener.DeviceListen(parsedCfg) |
365 | + if err != nil { |
366 | + BootLogFatalf("start device listening: %v", err) |
367 | + } |
368 | + BootLogListener("devices", lst) |
369 | + return func() { |
370 | + err = lst.AcceptLoop(session, logger) |
371 | + if err != nil { |
372 | + BootLogFatalf("accepting device connections: %v", err) |
373 | + } |
374 | + } |
375 | +} |
376 | |
377 | === renamed file 'server/dev/http.go' => 'server/dev/runner_http.go' |
378 | --- server/dev/http.go 2014-01-14 15:35:20 +0000 |
379 | +++ server/dev/runner_http.go 2014-01-22 09:51:22 +0000 |
380 | @@ -17,24 +17,34 @@ |
381 | package main |
382 | |
383 | import ( |
384 | + "launchpad.net/ubuntu-push/config" |
385 | "net" |
386 | "net/http" |
387 | - "time" |
388 | ) |
389 | |
390 | -// A HTTPServeConfig holds the HTTP server config. |
391 | -type HTTPServeConfig interface { |
392 | - HTTPAddr() string |
393 | - HTTPReadTimeout() time.Duration |
394 | - HTTPWriteTimeout() time.Duration |
395 | +// A HTTPServeParsedConfig holds and can be used to parse the HTTP server config. |
396 | +type HTTPServeParsedConfig struct { |
397 | + ParsedHTTPAddr config.ConfigHostPort `json:"http_addr"` |
398 | + ParsedHTTPReadTimeout config.ConfigTimeDuration `json:"http_read_timeout"` |
399 | + ParsedHTTPWriteTimeout config.ConfigTimeDuration `json:"http_write_timeout"` |
400 | } |
401 | |
402 | -// RunHTTPServe serves HTTP requests. |
403 | -func RunHTTPServe(lst net.Listener, h http.Handler, cfg HTTPServeConfig) error { |
404 | +// HTTPServeRunner returns a function to serve HTTP requests. |
405 | +func HTTPServeRunner(h http.Handler, parsedCfg *HTTPServeParsedConfig) func() { |
406 | + httpLst, err := net.Listen("tcp", parsedCfg.ParsedHTTPAddr.HostPort()) |
407 | + if err != nil { |
408 | + BootLogFatalf("start http listening: %v", err) |
409 | + } |
410 | + BootLogListener("http", httpLst) |
411 | srv := &http.Server{ |
412 | Handler: h, |
413 | - ReadTimeout: cfg.HTTPReadTimeout(), |
414 | - WriteTimeout: cfg.HTTPReadTimeout(), |
415 | - } |
416 | - return srv.Serve(lst) |
417 | + ReadTimeout: parsedCfg.ParsedHTTPReadTimeout.TimeDuration(), |
418 | + WriteTimeout: parsedCfg.ParsedHTTPWriteTimeout.TimeDuration(), |
419 | + } |
420 | + return func() { |
421 | + err := srv.Serve(httpLst) |
422 | + if err != nil { |
423 | + BootLogFatalf("accepting http connections: %v", err) |
424 | + } |
425 | + } |
426 | } |
427 | |
428 | === renamed file 'server/dev/http_test.go' => 'server/dev/runner_test.go' |
429 | --- server/dev/http_test.go 2014-01-14 15:35:20 +0000 |
430 | +++ server/dev/runner_test.go 2014-01-22 09:51:22 +0000 |
431 | @@ -17,54 +17,100 @@ |
432 | package main |
433 | |
434 | import ( |
435 | + "bytes" |
436 | "fmt" |
437 | "io/ioutil" |
438 | . "launchpad.net/gocheck" |
439 | - // "log" |
440 | + "launchpad.net/ubuntu-push/config" |
441 | + "launchpad.net/ubuntu-push/logger" |
442 | + helpers "launchpad.net/ubuntu-push/testing" |
443 | "net" |
444 | "net/http" |
445 | "time" |
446 | ) |
447 | |
448 | -type httpSuite struct{} |
449 | - |
450 | -var _ = Suite(&httpSuite{}) |
451 | - |
452 | -type testHTTPServeConfig struct{} |
453 | - |
454 | -func (cfg testHTTPServeConfig) HTTPAddr() string { |
455 | - return "127.0.0.1:0" |
456 | -} |
457 | - |
458 | -func (cfg testHTTPServeConfig) HTTPReadTimeout() time.Duration { |
459 | - return 5 * time.Second |
460 | -} |
461 | - |
462 | -func (cfg testHTTPServeConfig) HTTPWriteTimeout() time.Duration { |
463 | - return 5 * time.Second |
464 | +type runnerSuite struct { |
465 | + prevBootLogListener func(string, net.Listener) |
466 | + prevBootLogFatalf func(string, ...interface{}) |
467 | + lst net.Listener |
468 | + kind string |
469 | +} |
470 | + |
471 | +var _ = Suite(&runnerSuite{}) |
472 | + |
473 | +func (s *runnerSuite) SetUpSuite(c *C) { |
474 | + s.prevBootLogFatalf = BootLogFatalf |
475 | + s.prevBootLogListener = BootLogListener |
476 | + BootLogFatalf = func(format string, v ...interface{}) { |
477 | + panic(fmt.Sprintf(format, v...)) |
478 | + } |
479 | + BootLogListener = func(kind string, lst net.Listener) { |
480 | + s.kind = kind |
481 | + s.lst = lst |
482 | + } |
483 | +} |
484 | + |
485 | +func (s *runnerSuite) TearDownSuite(c *C) { |
486 | + BootLogListener = s.prevBootLogListener |
487 | + BootLogFatalf = s.prevBootLogFatalf |
488 | +} |
489 | + |
490 | +var testHTTPServeParsedConfig = HTTPServeParsedConfig{ |
491 | + "127.0.0.1:0", |
492 | + config.ConfigTimeDuration{5 * time.Second}, |
493 | + config.ConfigTimeDuration{5 * time.Second}, |
494 | } |
495 | |
496 | func testHandle(w http.ResponseWriter, r *http.Request) { |
497 | fmt.Fprintf(w, "yay!\n") |
498 | } |
499 | |
500 | -func (s *httpSuite) TestRunHTTPServe(c *C) { |
501 | - cfg := testHTTPServeConfig{} |
502 | - lst, err := net.Listen("tcp", cfg.HTTPAddr()) |
503 | - c.Assert(err, IsNil) |
504 | - defer lst.Close() |
505 | - errCh := make(chan error, 1) |
506 | +func (s *runnerSuite) TestHTTPServeRunner(c *C) { |
507 | + errCh := make(chan interface{}, 1) |
508 | h := http.HandlerFunc(testHandle) |
509 | + runner := HTTPServeRunner(h, &testHTTPServeParsedConfig) |
510 | + c.Assert(s.lst, Not(IsNil)) |
511 | + defer s.lst.Close() |
512 | + c.Check(s.kind, Equals, "http") |
513 | go func() { |
514 | - errCh <- RunHTTPServe(lst, h, cfg) |
515 | + defer func() { |
516 | + errCh <- recover() |
517 | + }() |
518 | + runner() |
519 | }() |
520 | - resp, err := http.Get(fmt.Sprintf("http://%s/", lst.Addr())) |
521 | + resp, err := http.Get(fmt.Sprintf("http://%s/", s.lst.Addr())) |
522 | c.Assert(err, IsNil) |
523 | defer resp.Body.Close() |
524 | c.Assert(resp.StatusCode, Equals, 200) |
525 | body, err := ioutil.ReadAll(resp.Body) |
526 | c.Assert(err, IsNil) |
527 | c.Check(string(body), Equals, "yay!\n") |
528 | - lst.Close() |
529 | - c.Check(<-errCh, ErrorMatches, ".*closed.*") |
530 | + s.lst.Close() |
531 | + c.Check(<-errCh, Matches, "accepting http connections:.*closed.*") |
532 | +} |
533 | + |
534 | +var testDevicesParsedConfig = DevicesParsedConfig{ |
535 | + ParsedPingInterval: config.ConfigTimeDuration{60 * time.Second}, |
536 | + ParsedExchangeTimeout: config.ConfigTimeDuration{10 * time.Second}, |
537 | + ParsedBrokerQueueSize: config.ConfigQueueSize(1000), |
538 | + ParsedSessionQueueSize: config.ConfigQueueSize(10), |
539 | + ParsedAddr: "127.0.0.1:0", |
540 | + ParsedKeyPEMFile: "", |
541 | + ParsedCertPEMFile: "", |
542 | + keyPEMBlock: helpers.TestKeyPEMBlock, |
543 | + certPEMBlock: helpers.TestCertPEMBlock, |
544 | +} |
545 | + |
546 | +func (s *runnerSuite) TestDevicesRunner(c *C) { |
547 | + buf := &bytes.Buffer{} |
548 | + prevBootLogger := BootLogger |
549 | + BootLogger = logger.NewSimpleLogger(buf, "debug") |
550 | + defer func() { |
551 | + BootLogger = prevBootLogger |
552 | + }() |
553 | + runner := DevicesRunner(func(conn net.Conn) error { return nil }, BootLogger, &testDevicesParsedConfig) |
554 | + c.Assert(s.lst, Not(IsNil)) |
555 | + s.lst.Close() |
556 | + c.Check(s.kind, Equals, "devices") |
557 | + c.Check(runner, PanicMatches, "accepting device connections:.*closed.*") |
558 | } |
559 | |
560 | === modified file 'server/dev/server.go' |
561 | --- server/dev/server.go 2014-01-17 17:21:35 +0000 |
562 | +++ server/dev/server.go 2014-01-22 09:51:22 +0000 |
563 | @@ -18,70 +18,48 @@ |
564 | package main |
565 | |
566 | import ( |
567 | + "launchpad.net/ubuntu-push/config" |
568 | "launchpad.net/ubuntu-push/logger" |
569 | "launchpad.net/ubuntu-push/server/api" |
570 | "launchpad.net/ubuntu-push/server/broker" |
571 | - "launchpad.net/ubuntu-push/server/listener" |
572 | "launchpad.net/ubuntu-push/server/session" |
573 | "launchpad.net/ubuntu-push/server/store" |
574 | "net" |
575 | "os" |
576 | "path/filepath" |
577 | - "syscall" |
578 | ) |
579 | |
580 | +type configuration struct { |
581 | + // device server configuration |
582 | + DevicesParsedConfig |
583 | + // api http server configuration |
584 | + HTTPServeParsedConfig |
585 | +} |
586 | + |
587 | func main() { |
588 | + cfgFpaths := os.Args[1:] |
589 | + cfg := &configuration{} |
590 | + err := config.ReadFiles(cfg, cfgFpaths...) |
591 | + if err != nil { |
592 | + BootLogFatalf("reading config: %v", err) |
593 | + } |
594 | + err = cfg.DevicesParsedConfig.FinishLoad(filepath.Dir(cfgFpaths[len(cfgFpaths)-1])) |
595 | + if err != nil { |
596 | + BootLogFatalf("reading config: %v", err) |
597 | + } |
598 | logger := logger.NewSimpleLogger(os.Stderr, "debug") |
599 | - if len(os.Args) < 2 { // xxx use flag |
600 | - logger.Fatalf("missing config file") |
601 | - } |
602 | - configFName := os.Args[1] |
603 | - f, err := os.Open(configFName) |
604 | - if err != nil { |
605 | - logger.Fatalf("reading config: %v", err) |
606 | - } |
607 | - cfg := &configuration{} |
608 | - err = cfg.read(f, filepath.Dir(configFName)) |
609 | - if err != nil { |
610 | - logger.Fatalf("reading config: %v", err) |
611 | - } |
612 | // setup a pending store and start the broker |
613 | sto := store.NewInMemoryPendingStore() |
614 | broker := broker.NewSimpleBroker(sto, cfg, logger) |
615 | broker.Start() |
616 | defer broker.Stop() |
617 | // serve the http api |
618 | - httpLst, err := net.Listen("tcp", cfg.HTTPAddr()) |
619 | - if err != nil { |
620 | - logger.Fatalf("start http listening: %v", err) |
621 | - } |
622 | handler := api.MakeHandlersMux(sto, broker, logger) |
623 | handler = api.PanicTo500Handler(handler, logger) |
624 | - logger.Infof("listening for http on %v", httpLst.Addr()) |
625 | - go func() { |
626 | - err := RunHTTPServe(httpLst, handler, cfg) |
627 | - if err != nil { |
628 | - logger.Fatalf("accepting http connections: %v", err) |
629 | - } |
630 | - }() |
631 | + go HTTPServeRunner(handler, &cfg.HTTPServeParsedConfig)() |
632 | // listen for device connections |
633 | - logger.Debugf("PingInterval: %s, ExchangeTimeout %s", cfg.PingInterval(), cfg.ExchangeTimeout()) |
634 | - var rlim syscall.Rlimit |
635 | - err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim) |
636 | - if err != nil { |
637 | - logger.Fatalf("getrlimit failed: %v", err) |
638 | - } |
639 | - logger.Debugf("nofile soft: %d hard: %d", rlim.Cur, rlim.Max) |
640 | - lst, err := listener.DeviceListen(cfg) |
641 | - if err != nil { |
642 | - logger.Fatalf("start device listening: %v", err) |
643 | - } |
644 | - logger.Infof("listening for devices on %v", lst.Addr()) |
645 | - err = lst.AcceptLoop(func(conn net.Conn) error { |
646 | + DevicesRunner(func(conn net.Conn) error { |
647 | track := session.NewTracker(logger) |
648 | return session.Session(conn, broker, cfg, track) |
649 | - }, logger) |
650 | - if err != nil { |
651 | - logger.Fatalf("accepting device connections: %v", err) |
652 | - } |
653 | + }, logger, &cfg.DevicesParsedConfig)() |
654 | } |
Lovely! :-)