Browse code

Remove engine mechanism

Signed-off-by: Antonio Murdaca <me@runcom.ninja>

Antonio Murdaca authored on 2015/04/28 06:11:29
Showing 20 changed files
... ...
@@ -1,13 +1,14 @@
1 1
 package client
2 2
 
3 3
 import (
4
+	"encoding/json"
4 5
 	"fmt"
5 6
 	"io"
6 7
 	"net/url"
7 8
 	"os"
8 9
 
9 10
 	"github.com/Sirupsen/logrus"
10
-	"github.com/docker/docker/engine"
11
+	"github.com/docker/docker/api/types"
11 12
 	flag "github.com/docker/docker/pkg/mflag"
12 13
 	"github.com/docker/docker/pkg/promise"
13 14
 	"github.com/docker/docker/pkg/signal"
... ...
@@ -65,12 +66,12 @@ func (cli *DockerCli) CmdStart(args ...string) error {
65 65
 			return err
66 66
 		}
67 67
 
68
-		env := engine.Env{}
69
-		if err := env.Decode(stream); err != nil {
68
+		var c types.ContainerJSON
69
+		if err := json.NewDecoder(stream).Decode(&c); err != nil {
70 70
 			return err
71 71
 		}
72
-		config := env.GetSubEnv("Config")
73
-		tty = config.GetBool("Tty")
72
+
73
+		tty = c.Config.Tty
74 74
 
75 75
 		if !tty {
76 76
 			sigc := cli.forwardAllSignals(cmd.Arg(0))
... ...
@@ -82,7 +83,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
82 82
 		v := url.Values{}
83 83
 		v.Set("stream", "1")
84 84
 
85
-		if *openStdin && config.GetBool("OpenStdin") {
85
+		if *openStdin && c.Config.OpenStdin {
86 86
 			v.Set("stdin", "1")
87 87
 			in = cli.in
88 88
 		}
... ...
@@ -22,7 +22,6 @@ import (
22 22
 	"github.com/docker/docker/api/types"
23 23
 	"github.com/docker/docker/autogen/dockerversion"
24 24
 	"github.com/docker/docker/cliconfig"
25
-	"github.com/docker/docker/engine"
26 25
 	"github.com/docker/docker/pkg/jsonmessage"
27 26
 	"github.com/docker/docker/pkg/signal"
28 27
 	"github.com/docker/docker/pkg/stdcopy"
... ...
@@ -42,18 +41,8 @@ func (cli *DockerCli) HTTPClient() *http.Client {
42 42
 func (cli *DockerCli) encodeData(data interface{}) (*bytes.Buffer, error) {
43 43
 	params := bytes.NewBuffer(nil)
44 44
 	if data != nil {
45
-		if env, ok := data.(engine.Env); ok {
46
-			if err := env.Encode(params); err != nil {
47
-				return nil, err
48
-			}
49
-		} else {
50
-			buf, err := json.Marshal(data)
51
-			if err != nil {
52
-				return nil, err
53
-			}
54
-			if _, err := params.Write(buf); err != nil {
55
-				return nil, err
56
-			}
45
+		if err := json.NewEncoder(params).Encode(data); err != nil {
46
+			return nil, err
57 47
 		}
58 48
 	}
59 49
 	return params, nil
... ...
@@ -1,13 +1,14 @@
1 1
 package client
2 2
 
3 3
 import (
4
+	"encoding/json"
4 5
 	"fmt"
5 6
 	"runtime"
6 7
 
7 8
 	"github.com/Sirupsen/logrus"
8 9
 	"github.com/docker/docker/api"
10
+	"github.com/docker/docker/api/types"
9 11
 	"github.com/docker/docker/autogen/dockerversion"
10
-	"github.com/docker/docker/engine"
11 12
 	flag "github.com/docker/docker/pkg/mflag"
12 13
 )
13 14
 
... ...
@@ -32,28 +33,24 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
32 32
 	}
33 33
 	fmt.Fprintf(cli.out, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH)
34 34
 
35
-	body, _, err := readBody(cli.call("GET", "/version", nil, nil))
35
+	stream, _, err := cli.call("GET", "/version", nil, nil)
36 36
 	if err != nil {
37 37
 		return err
38 38
 	}
39 39
 
40
-	out := engine.NewOutput()
41
-	remoteVersion, err := out.AddEnv()
42
-	if err != nil {
43
-		logrus.Errorf("Error reading remote version: %s", err)
44
-		return err
45
-	}
46
-	if _, err := out.Write(body); err != nil {
40
+	var v types.Version
41
+	if err := json.NewDecoder(stream).Decode(&v); err != nil {
47 42
 		logrus.Errorf("Error reading remote version: %s", err)
48 43
 		return err
49 44
 	}
50
-	out.Close()
51
-	fmt.Fprintf(cli.out, "Server version: %s\n", remoteVersion.Get("Version"))
52
-	if apiVersion := remoteVersion.Get("ApiVersion"); apiVersion != "" {
53
-		fmt.Fprintf(cli.out, "Server API version: %s\n", apiVersion)
45
+
46
+	fmt.Fprintf(cli.out, "Server version: %s\n", v.Version)
47
+	if v.ApiVersion != "" {
48
+		fmt.Fprintf(cli.out, "Server API version: %s\n", v.ApiVersion)
54 49
 	}
55
-	fmt.Fprintf(cli.out, "Go version (server): %s\n", remoteVersion.Get("GoVersion"))
56
-	fmt.Fprintf(cli.out, "Git commit (server): %s\n", remoteVersion.Get("GitCommit"))
57
-	fmt.Fprintf(cli.out, "OS/Arch (server): %s/%s\n", remoteVersion.Get("Os"), remoteVersion.Get("Arch"))
50
+	fmt.Fprintf(cli.out, "Go version (server): %s\n", v.GoVersion)
51
+	fmt.Fprintf(cli.out, "Git commit (server): %s\n", v.GitCommit)
52
+	fmt.Fprintf(cli.out, "OS/Arch (server): %s/%s\n", v.Os, v.Arch)
53
+
58 54
 	return nil
59 55
 }
... ...
@@ -1,9 +1,6 @@
1 1
 package server
2 2
 
3 3
 import (
4
-	"runtime"
5
-	"time"
6
-
7 4
 	"encoding/base64"
8 5
 	"encoding/json"
9 6
 	"fmt"
... ...
@@ -11,8 +8,10 @@ import (
11 11
 	"net"
12 12
 	"net/http"
13 13
 	"os"
14
+	"runtime"
14 15
 	"strconv"
15 16
 	"strings"
17
+	"time"
16 18
 
17 19
 	"code.google.com/p/go.net/websocket"
18 20
 	"github.com/gorilla/mux"
... ...
@@ -25,7 +24,6 @@ import (
25 25
 	"github.com/docker/docker/cliconfig"
26 26
 	"github.com/docker/docker/daemon"
27 27
 	"github.com/docker/docker/daemon/networkdriver/bridge"
28
-	"github.com/docker/docker/engine"
29 28
 	"github.com/docker/docker/graph"
30 29
 	"github.com/docker/docker/pkg/jsonmessage"
31 30
 	"github.com/docker/docker/pkg/parsers"
... ...
@@ -53,26 +51,31 @@ type ServerConfig struct {
53 53
 }
54 54
 
55 55
 type Server struct {
56
-	daemon *daemon.Daemon
57
-	cfg    *ServerConfig
58
-	router *mux.Router
59
-	start  chan struct{}
60
-
61
-	// TODO: delete engine
62
-	eng *engine.Engine
56
+	daemon  *daemon.Daemon
57
+	cfg     *ServerConfig
58
+	router  *mux.Router
59
+	start   chan struct{}
60
+	servers []serverCloser
63 61
 }
64 62
 
65
-func New(cfg *ServerConfig, eng *engine.Engine) *Server {
63
+func New(cfg *ServerConfig) *Server {
66 64
 	srv := &Server{
67 65
 		cfg:   cfg,
68 66
 		start: make(chan struct{}),
69
-		eng:   eng,
70 67
 	}
71
-	r := createRouter(srv, eng)
68
+	r := createRouter(srv)
72 69
 	srv.router = r
73 70
 	return srv
74 71
 }
75 72
 
73
+func (s *Server) Close() {
74
+	for _, srv := range s.servers {
75
+		if err := srv.Close(); err != nil {
76
+			logrus.Error(err)
77
+		}
78
+	}
79
+}
80
+
76 81
 func (s *Server) SetDaemon(d *daemon.Daemon) {
77 82
 	s.daemon = d
78 83
 }
... ...
@@ -92,19 +95,15 @@ func (s *Server) ServeApi(protoAddrs []string) error {
92 92
 		if len(protoAddrParts) != 2 {
93 93
 			return fmt.Errorf("bad format, expected PROTO://ADDR")
94 94
 		}
95
+		srv, err := s.newServer(protoAddrParts[0], protoAddrParts[1])
96
+		if err != nil {
97
+			return err
98
+		}
99
+		s.servers = append(s.servers, srv)
100
+
95 101
 		go func(proto, addr string) {
96 102
 			logrus.Infof("Listening for HTTP on %s (%s)", proto, addr)
97
-			srv, err := s.newServer(proto, addr)
98
-			if err != nil {
99
-				chErrors <- err
100
-				return
101
-			}
102
-			s.eng.OnShutdown(func() {
103
-				if err := srv.Close(); err != nil {
104
-					logrus.Error(err)
105
-				}
106
-			})
107
-			if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
103
+			if err := srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
108 104
 				err = nil
109 105
 			}
110 106
 			chErrors <- err
... ...
@@ -133,7 +132,7 @@ func (s *HttpServer) Close() error {
133 133
 	return s.l.Close()
134 134
 }
135 135
 
136
-type HttpApiFunc func(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error
136
+type HttpApiFunc func(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error
137 137
 
138 138
 func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
139 139
 	conn, _, err := w.(http.Hijacker).Hijack()
... ...
@@ -230,16 +229,7 @@ func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
230 230
 	return json.NewEncoder(w).Encode(v)
231 231
 }
232 232
 
233
-func streamJSON(out *engine.Output, w http.ResponseWriter, flush bool) {
234
-	w.Header().Set("Content-Type", "application/json")
235
-	if flush {
236
-		out.Add(utils.NewWriteFlusher(w))
237
-	} else {
238
-		out.Add(w)
239
-	}
240
-}
241
-
242
-func (s *Server) postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
233
+func (s *Server) postAuth(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
243 234
 	var config *cliconfig.AuthConfig
244 235
 	err := json.NewDecoder(r.Body).Decode(&config)
245 236
 	r.Body.Close()
... ...
@@ -255,7 +245,7 @@ func (s *Server) postAuth(eng *engine.Engine, version version.Version, w http.Re
255 255
 	})
256 256
 }
257 257
 
258
-func (s *Server) getVersion(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
258
+func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
259 259
 	w.Header().Set("Content-Type", "application/json")
260 260
 
261 261
 	v := &types.Version{
... ...
@@ -273,7 +263,7 @@ func (s *Server) getVersion(eng *engine.Engine, version version.Version, w http.
273 273
 	return writeJSON(w, http.StatusOK, v)
274 274
 }
275 275
 
276
-func (s *Server) postContainersKill(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
276
+func (s *Server) postContainersKill(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
277 277
 	if vars == nil {
278 278
 		return fmt.Errorf("Missing parameter")
279 279
 	}
... ...
@@ -308,7 +298,7 @@ func (s *Server) postContainersKill(eng *engine.Engine, version version.Version,
308 308
 	return nil
309 309
 }
310 310
 
311
-func (s *Server) postContainersPause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
311
+func (s *Server) postContainersPause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
312 312
 	if vars == nil {
313 313
 		return fmt.Errorf("Missing parameter")
314 314
 	}
... ...
@@ -332,7 +322,7 @@ func (s *Server) postContainersPause(eng *engine.Engine, version version.Version
332 332
 	return nil
333 333
 }
334 334
 
335
-func (s *Server) postContainersUnpause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
335
+func (s *Server) postContainersUnpause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
336 336
 	if vars == nil {
337 337
 		return fmt.Errorf("Missing parameter")
338 338
 	}
... ...
@@ -356,7 +346,7 @@ func (s *Server) postContainersUnpause(eng *engine.Engine, version version.Versi
356 356
 	return nil
357 357
 }
358 358
 
359
-func (s *Server) getContainersExport(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
359
+func (s *Server) getContainersExport(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
360 360
 	if vars == nil {
361 361
 		return fmt.Errorf("Missing parameter")
362 362
 	}
... ...
@@ -364,7 +354,7 @@ func (s *Server) getContainersExport(eng *engine.Engine, version version.Version
364 364
 	return s.daemon.ContainerExport(vars["name"], w)
365 365
 }
366 366
 
367
-func (s *Server) getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
367
+func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
368 368
 	if err := parseForm(r); err != nil {
369 369
 		return err
370 370
 	}
... ...
@@ -405,7 +395,7 @@ func (s *Server) getImagesJSON(eng *engine.Engine, version version.Version, w ht
405 405
 	return writeJSON(w, http.StatusOK, legacyImages)
406 406
 }
407 407
 
408
-func (s *Server) getInfo(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
408
+func (s *Server) getInfo(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
409 409
 	w.Header().Set("Content-Type", "application/json")
410 410
 
411 411
 	info, err := s.daemon.SystemInfo()
... ...
@@ -416,7 +406,7 @@ func (s *Server) getInfo(eng *engine.Engine, version version.Version, w http.Res
416 416
 	return writeJSON(w, http.StatusOK, info)
417 417
 }
418 418
 
419
-func (s *Server) getEvents(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
419
+func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
420 420
 	if err := parseForm(r); err != nil {
421 421
 		return err
422 422
 	}
... ...
@@ -520,7 +510,7 @@ func (s *Server) getEvents(eng *engine.Engine, version version.Version, w http.R
520 520
 	}
521 521
 }
522 522
 
523
-func (s *Server) getImagesHistory(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
523
+func (s *Server) getImagesHistory(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
524 524
 	if vars == nil {
525 525
 		return fmt.Errorf("Missing parameter")
526 526
 	}
... ...
@@ -534,7 +524,7 @@ func (s *Server) getImagesHistory(eng *engine.Engine, version version.Version, w
534 534
 	return writeJSON(w, http.StatusOK, history)
535 535
 }
536 536
 
537
-func (s *Server) getContainersChanges(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
537
+func (s *Server) getContainersChanges(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
538 538
 	if vars == nil {
539 539
 		return fmt.Errorf("Missing parameter")
540 540
 	}
... ...
@@ -553,7 +543,7 @@ func (s *Server) getContainersChanges(eng *engine.Engine, version version.Versio
553 553
 	return writeJSON(w, http.StatusOK, changes)
554 554
 }
555 555
 
556
-func (s *Server) getContainersTop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
556
+func (s *Server) getContainersTop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
557 557
 	if version.LessThan("1.4") {
558 558
 		return fmt.Errorf("top was improved a lot since 1.3, Please upgrade your docker client.")
559 559
 	}
... ...
@@ -574,7 +564,7 @@ func (s *Server) getContainersTop(eng *engine.Engine, version version.Version, w
574 574
 	return writeJSON(w, http.StatusOK, procList)
575 575
 }
576 576
 
577
-func (s *Server) getContainersJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
577
+func (s *Server) getContainersJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
578 578
 	if err := parseForm(r); err != nil {
579 579
 		return err
580 580
 	}
... ...
@@ -603,7 +593,7 @@ func (s *Server) getContainersJSON(eng *engine.Engine, version version.Version,
603 603
 	return writeJSON(w, http.StatusOK, containers)
604 604
 }
605 605
 
606
-func (s *Server) getContainersStats(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
606
+func (s *Server) getContainersStats(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
607 607
 	if err := parseForm(r); err != nil {
608 608
 		return err
609 609
 	}
... ...
@@ -614,7 +604,7 @@ func (s *Server) getContainersStats(eng *engine.Engine, version version.Version,
614 614
 	return s.daemon.ContainerStats(vars["name"], utils.NewWriteFlusher(w))
615 615
 }
616 616
 
617
-func (s *Server) getContainersLogs(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
617
+func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
618 618
 	if err := parseForm(r); err != nil {
619 619
 		return err
620 620
 	}
... ...
@@ -644,7 +634,7 @@ func (s *Server) getContainersLogs(eng *engine.Engine, version version.Version,
644 644
 	return nil
645 645
 }
646 646
 
647
-func (s *Server) postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
647
+func (s *Server) postImagesTag(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
648 648
 	if err := parseForm(r); err != nil {
649 649
 		return err
650 650
 	}
... ...
@@ -662,7 +652,7 @@ func (s *Server) postImagesTag(eng *engine.Engine, version version.Version, w ht
662 662
 	return nil
663 663
 }
664 664
 
665
-func (s *Server) postCommit(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
665
+func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
666 666
 	if err := parseForm(r); err != nil {
667 667
 		return err
668 668
 	}
... ...
@@ -708,7 +698,7 @@ func (s *Server) postCommit(eng *engine.Engine, version version.Version, w http.
708 708
 }
709 709
 
710 710
 // Creates an image from Pull or from Import
711
-func (s *Server) postImagesCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
711
+func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
712 712
 	if err := parseForm(r); err != nil {
713 713
 		return err
714 714
 	}
... ...
@@ -788,7 +778,7 @@ func (s *Server) postImagesCreate(eng *engine.Engine, version version.Version, w
788 788
 	return nil
789 789
 }
790 790
 
791
-func (s *Server) getImagesSearch(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
791
+func (s *Server) getImagesSearch(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
792 792
 	if err := parseForm(r); err != nil {
793 793
 		return err
794 794
 	}
... ...
@@ -818,7 +808,7 @@ func (s *Server) getImagesSearch(eng *engine.Engine, version version.Version, w
818 818
 	return json.NewEncoder(w).Encode(query.Results)
819 819
 }
820 820
 
821
-func (s *Server) postImagesPush(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
821
+func (s *Server) postImagesPush(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
822 822
 	if vars == nil {
823 823
 		return fmt.Errorf("Missing parameter")
824 824
 	}
... ...
@@ -875,7 +865,7 @@ func (s *Server) postImagesPush(eng *engine.Engine, version version.Version, w h
875 875
 
876 876
 }
877 877
 
878
-func (s *Server) getImagesGet(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
878
+func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
879 879
 	if vars == nil {
880 880
 		return fmt.Errorf("Missing parameter")
881 881
 	}
... ...
@@ -907,11 +897,11 @@ func (s *Server) getImagesGet(eng *engine.Engine, version version.Version, w htt
907 907
 
908 908
 }
909 909
 
910
-func (s *Server) postImagesLoad(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
910
+func (s *Server) postImagesLoad(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
911 911
 	return s.daemon.Repositories().Load(r.Body, w)
912 912
 }
913 913
 
914
-func (s *Server) postContainersCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
914
+func (s *Server) postContainersCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
915 915
 	if err := parseForm(r); err != nil {
916 916
 		return nil
917 917
 	}
... ...
@@ -939,7 +929,7 @@ func (s *Server) postContainersCreate(eng *engine.Engine, version version.Versio
939 939
 	})
940 940
 }
941 941
 
942
-func (s *Server) postContainersRestart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
942
+func (s *Server) postContainersRestart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
943 943
 	if err := parseForm(r); err != nil {
944 944
 		return err
945 945
 	}
... ...
@@ -961,7 +951,7 @@ func (s *Server) postContainersRestart(eng *engine.Engine, version version.Versi
961 961
 	return nil
962 962
 }
963 963
 
964
-func (s *Server) postContainerRename(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
964
+func (s *Server) postContainerRename(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
965 965
 	if err := parseForm(r); err != nil {
966 966
 		return err
967 967
 	}
... ...
@@ -978,7 +968,7 @@ func (s *Server) postContainerRename(eng *engine.Engine, version version.Version
978 978
 	return nil
979 979
 }
980 980
 
981
-func (s *Server) deleteContainers(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
981
+func (s *Server) deleteContainers(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
982 982
 	if err := parseForm(r); err != nil {
983 983
 		return err
984 984
 	}
... ...
@@ -1006,7 +996,7 @@ func (s *Server) deleteContainers(eng *engine.Engine, version version.Version, w
1006 1006
 	return nil
1007 1007
 }
1008 1008
 
1009
-func (s *Server) deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1009
+func (s *Server) deleteImages(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1010 1010
 	if err := parseForm(r); err != nil {
1011 1011
 		return err
1012 1012
 	}
... ...
@@ -1026,7 +1016,7 @@ func (s *Server) deleteImages(eng *engine.Engine, version version.Version, w htt
1026 1026
 	return writeJSON(w, http.StatusOK, list)
1027 1027
 }
1028 1028
 
1029
-func (s *Server) postContainersStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1029
+func (s *Server) postContainersStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1030 1030
 	if vars == nil {
1031 1031
 		return fmt.Errorf("Missing parameter")
1032 1032
 	}
... ...
@@ -1062,7 +1052,7 @@ func (s *Server) postContainersStart(eng *engine.Engine, version version.Version
1062 1062
 	return nil
1063 1063
 }
1064 1064
 
1065
-func (s *Server) postContainersStop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1065
+func (s *Server) postContainersStop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1066 1066
 	if err := parseForm(r); err != nil {
1067 1067
 		return err
1068 1068
 	}
... ...
@@ -1087,7 +1077,7 @@ func (s *Server) postContainersStop(eng *engine.Engine, version version.Version,
1087 1087
 	return nil
1088 1088
 }
1089 1089
 
1090
-func (s *Server) postContainersWait(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1090
+func (s *Server) postContainersWait(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1091 1091
 	if vars == nil {
1092 1092
 		return fmt.Errorf("Missing parameter")
1093 1093
 	}
... ...
@@ -1105,7 +1095,7 @@ func (s *Server) postContainersWait(eng *engine.Engine, version version.Version,
1105 1105
 	})
1106 1106
 }
1107 1107
 
1108
-func (s *Server) postContainersResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1108
+func (s *Server) postContainersResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1109 1109
 	if err := parseForm(r); err != nil {
1110 1110
 		return err
1111 1111
 	}
... ...
@@ -1130,7 +1120,7 @@ func (s *Server) postContainersResize(eng *engine.Engine, version version.Versio
1130 1130
 	return cont.Resize(height, width)
1131 1131
 }
1132 1132
 
1133
-func (s *Server) postContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1133
+func (s *Server) postContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1134 1134
 	if err := parseForm(r); err != nil {
1135 1135
 		return err
1136 1136
 	}
... ...
@@ -1185,7 +1175,7 @@ func (s *Server) postContainersAttach(eng *engine.Engine, version version.Versio
1185 1185
 	return nil
1186 1186
 }
1187 1187
 
1188
-func (s *Server) wsContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1188
+func (s *Server) wsContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1189 1189
 	if err := parseForm(r); err != nil {
1190 1190
 		return err
1191 1191
 	}
... ...
@@ -1211,7 +1201,7 @@ func (s *Server) wsContainersAttach(eng *engine.Engine, version version.Version,
1211 1211
 	return nil
1212 1212
 }
1213 1213
 
1214
-func (s *Server) getContainersByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1214
+func (s *Server) getContainersByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1215 1215
 	if vars == nil {
1216 1216
 		return fmt.Errorf("Missing parameter")
1217 1217
 	}
... ...
@@ -1232,7 +1222,7 @@ func (s *Server) getContainersByName(eng *engine.Engine, version version.Version
1232 1232
 	return writeJSON(w, http.StatusOK, containerJSON)
1233 1233
 }
1234 1234
 
1235
-func (s *Server) getExecByID(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1235
+func (s *Server) getExecByID(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1236 1236
 	if vars == nil {
1237 1237
 		return fmt.Errorf("Missing parameter 'id'")
1238 1238
 	}
... ...
@@ -1245,7 +1235,7 @@ func (s *Server) getExecByID(eng *engine.Engine, version version.Version, w http
1245 1245
 	return writeJSON(w, http.StatusOK, eConfig)
1246 1246
 }
1247 1247
 
1248
-func (s *Server) getImagesByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1248
+func (s *Server) getImagesByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1249 1249
 	if vars == nil {
1250 1250
 		return fmt.Errorf("Missing parameter")
1251 1251
 	}
... ...
@@ -1268,7 +1258,7 @@ func (s *Server) getImagesByName(eng *engine.Engine, version version.Version, w
1268 1268
 	return writeJSON(w, http.StatusOK, imageInspect)
1269 1269
 }
1270 1270
 
1271
-func (s *Server) postBuild(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1271
+func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1272 1272
 	if version.LessThan("1.3") {
1273 1273
 		return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.")
1274 1274
 	}
... ...
@@ -1363,7 +1353,7 @@ func (s *Server) postBuild(eng *engine.Engine, version version.Version, w http.R
1363 1363
 	return nil
1364 1364
 }
1365 1365
 
1366
-func (s *Server) postContainersCopy(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1366
+func (s *Server) postContainersCopy(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1367 1367
 	if vars == nil {
1368 1368
 		return fmt.Errorf("Missing parameter")
1369 1369
 	}
... ...
@@ -1413,7 +1403,7 @@ func (s *Server) postContainersCopy(eng *engine.Engine, version version.Version,
1413 1413
 	return nil
1414 1414
 }
1415 1415
 
1416
-func (s *Server) postContainerExecCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1416
+func (s *Server) postContainerExecCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1417 1417
 	if err := parseForm(r); err != nil {
1418 1418
 		return nil
1419 1419
 	}
... ...
@@ -1442,7 +1432,7 @@ func (s *Server) postContainerExecCreate(eng *engine.Engine, version version.Ver
1442 1442
 }
1443 1443
 
1444 1444
 // TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
1445
-func (s *Server) postContainerExecStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1445
+func (s *Server) postContainerExecStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1446 1446
 	if err := parseForm(r); err != nil {
1447 1447
 		return nil
1448 1448
 	}
... ...
@@ -1495,7 +1485,7 @@ func (s *Server) postContainerExecStart(eng *engine.Engine, version version.Vers
1495 1495
 	return nil
1496 1496
 }
1497 1497
 
1498
-func (s *Server) postContainerExecResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1498
+func (s *Server) postContainerExecResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1499 1499
 	if err := parseForm(r); err != nil {
1500 1500
 		return err
1501 1501
 	}
... ...
@@ -1515,7 +1505,7 @@ func (s *Server) postContainerExecResize(eng *engine.Engine, version version.Ver
1515 1515
 	return s.daemon.ContainerExecResize(vars["name"], height, width)
1516 1516
 }
1517 1517
 
1518
-func (s *Server) optionsHandler(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1518
+func (s *Server) optionsHandler(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1519 1519
 	w.WriteHeader(http.StatusOK)
1520 1520
 	return nil
1521 1521
 }
... ...
@@ -1526,12 +1516,12 @@ func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string
1526 1526
 	w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
1527 1527
 }
1528 1528
 
1529
-func (s *Server) ping(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1529
+func (s *Server) ping(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1530 1530
 	_, err := w.Write([]byte{'O', 'K'})
1531 1531
 	return err
1532 1532
 }
1533 1533
 
1534
-func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, corsHeaders string, dockerVersion version.Version) http.HandlerFunc {
1534
+func makeHttpHandler(logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, corsHeaders string, dockerVersion version.Version) http.HandlerFunc {
1535 1535
 	return func(w http.ResponseWriter, r *http.Request) {
1536 1536
 		// log the request
1537 1537
 		logrus.Debugf("Calling %s %s", localMethod, localRoute)
... ...
@@ -1559,7 +1549,7 @@ func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, local
1559 1559
 			return
1560 1560
 		}
1561 1561
 
1562
-		if err := handlerFunc(eng, version, w, r, mux.Vars(r)); err != nil {
1562
+		if err := handlerFunc(version, w, r, mux.Vars(r)); err != nil {
1563 1563
 			logrus.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err)
1564 1564
 			httpError(w, err)
1565 1565
 		}
... ...
@@ -1567,7 +1557,7 @@ func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, local
1567 1567
 }
1568 1568
 
1569 1569
 // we keep enableCors just for legacy usage, need to be removed in the future
1570
-func createRouter(s *Server, eng *engine.Engine) *mux.Router {
1570
+func createRouter(s *Server) *mux.Router {
1571 1571
 	r := mux.NewRouter()
1572 1572
 	if os.Getenv("DEBUG") != "" {
1573 1573
 		ProfilerSetup(r, "/debug/")
... ...
@@ -1644,7 +1634,7 @@ func createRouter(s *Server, eng *engine.Engine) *mux.Router {
1644 1644
 			localMethod := method
1645 1645
 
1646 1646
 			// build the handler function
1647
-			f := makeHttpHandler(eng, s.cfg.Logging, localMethod, localRoute, localFct, corsHeaders, version.Version(s.cfg.Version))
1647
+			f := makeHttpHandler(s.cfg.Logging, localMethod, localRoute, localFct, corsHeaders, version.Version(s.cfg.Version))
1648 1648
 
1649 1649
 			// add the new route
1650 1650
 			if localRoute == "" {
... ...
@@ -1659,23 +1649,6 @@ func createRouter(s *Server, eng *engine.Engine) *mux.Router {
1659 1659
 	return r
1660 1660
 }
1661 1661
 
1662
-// ServeRequest processes a single http request to the docker remote api.
1663
-// FIXME: refactor this to be part of Server and not require re-creating a new
1664
-// router each time. This requires first moving ListenAndServe into Server.
1665
-func ServeRequest(eng *engine.Engine, apiversion version.Version, w http.ResponseWriter, req *http.Request) {
1666
-	cfg := &ServerConfig{
1667
-		EnableCors: true,
1668
-		Version:    string(apiversion),
1669
-	}
1670
-	api := New(cfg, eng)
1671
-	daemon, _ := eng.HackGetGlobalVar("httpapi.daemon").(*daemon.Daemon)
1672
-	api.AcceptConnections(daemon)
1673
-	router := createRouter(api, eng)
1674
-	// Insert APIVERSION into the request as a convenience
1675
-	req.URL.Path = fmt.Sprintf("/v%s%s", apiversion, req.URL.Path)
1676
-	router.ServeHTTP(w, req)
1677
-}
1678
-
1679 1662
 func allocateDaemonPort(addr string) error {
1680 1663
 	host, port, err := net.SplitHostPort(addr)
1681 1664
 	if err != nil {
... ...
@@ -26,7 +26,6 @@ import (
26 26
 	"github.com/docker/docker/daemon/logger/syslog"
27 27
 	"github.com/docker/docker/daemon/network"
28 28
 	"github.com/docker/docker/daemon/networkdriver/bridge"
29
-	"github.com/docker/docker/engine"
30 29
 	"github.com/docker/docker/image"
31 30
 	"github.com/docker/docker/links"
32 31
 	"github.com/docker/docker/nat"
... ...
@@ -600,10 +599,7 @@ func (container *Container) AllocateNetwork() error {
600 600
 		return nil
601 601
 	}
602 602
 
603
-	var (
604
-		err error
605
-		eng = container.daemon.eng
606
-	)
603
+	var err error
607 604
 
608 605
 	networkSettings, err := bridge.Allocate(container.ID, container.Config.MacAddress, "", "")
609 606
 	if err != nil {
... ...
@@ -650,7 +646,7 @@ func (container *Container) AllocateNetwork() error {
650 650
 	container.NetworkSettings.PortMapping = nil
651 651
 
652 652
 	for port := range portSpecs {
653
-		if err = container.allocatePort(eng, port, bindings); err != nil {
653
+		if err = container.allocatePort(port, bindings); err != nil {
654 654
 			bridge.Release(container.ID)
655 655
 			return err
656 656
 		}
... ...
@@ -686,8 +682,6 @@ func (container *Container) RestoreNetwork() error {
686 686
 		return nil
687 687
 	}
688 688
 
689
-	eng := container.daemon.eng
690
-
691 689
 	// Re-allocate the interface with the same IP and MAC address.
692 690
 	if _, err := bridge.Allocate(container.ID, container.NetworkSettings.MacAddress, container.NetworkSettings.IPAddress, ""); err != nil {
693 691
 		return err
... ...
@@ -695,7 +689,7 @@ func (container *Container) RestoreNetwork() error {
695 695
 
696 696
 	// Re-allocate any previously allocated ports.
697 697
 	for port := range container.NetworkSettings.Ports {
698
-		if err := container.allocatePort(eng, port, container.NetworkSettings.Ports); err != nil {
698
+		if err := container.allocatePort(port, container.NetworkSettings.Ports); err != nil {
699 699
 			return err
700 700
 		}
701 701
 	}
... ...
@@ -1483,7 +1477,7 @@ func (container *Container) waitForStart() error {
1483 1483
 	return nil
1484 1484
 }
1485 1485
 
1486
-func (container *Container) allocatePort(eng *engine.Engine, port nat.Port, bindings nat.PortMap) error {
1486
+func (container *Container) allocatePort(port nat.Port, bindings nat.PortMap) error {
1487 1487
 	binding := bindings[port]
1488 1488
 	if container.hostConfig.PublishAllPorts && len(binding) == 0 {
1489 1489
 		binding = append(binding, nat.PortBinding{})
... ...
@@ -27,7 +27,6 @@ import (
27 27
 	_ "github.com/docker/docker/daemon/graphdriver/vfs"
28 28
 	"github.com/docker/docker/daemon/network"
29 29
 	"github.com/docker/docker/daemon/networkdriver/bridge"
30
-	"github.com/docker/docker/engine"
31 30
 	"github.com/docker/docker/graph"
32 31
 	"github.com/docker/docker/image"
33 32
 	"github.com/docker/docker/pkg/archive"
... ...
@@ -38,7 +37,6 @@ import (
38 38
 	"github.com/docker/docker/pkg/namesgenerator"
39 39
 	"github.com/docker/docker/pkg/parsers"
40 40
 	"github.com/docker/docker/pkg/parsers/kernel"
41
-	"github.com/docker/docker/pkg/pidfile"
42 41
 	"github.com/docker/docker/pkg/resolvconf"
43 42
 	"github.com/docker/docker/pkg/stringid"
44 43
 	"github.com/docker/docker/pkg/sysinfo"
... ...
@@ -103,7 +101,6 @@ type Daemon struct {
103 103
 	idIndex          *truncindex.TruncIndex
104 104
 	sysInfo          *sysinfo.SysInfo
105 105
 	volumes          *volumes.Repository
106
-	eng              *engine.Engine
107 106
 	config           *Config
108 107
 	containerGraph   *graphdb.Database
109 108
 	driver           graphdriver.Driver
... ...
@@ -114,14 +111,6 @@ type Daemon struct {
114 114
 	EventsService    *events.Events
115 115
 }
116 116
 
117
-// Install installs daemon capabilities to eng.
118
-func (daemon *Daemon) Install(eng *engine.Engine) error {
119
-	// FIXME: this hack is necessary for legacy integration tests to access
120
-	// the daemon object.
121
-	eng.HackSetGlobalVar("httpapi.daemon", daemon)
122
-	return nil
123
-}
124
-
125 117
 // Get looks for a container using the provided information, which could be
126 118
 // one of the following inputs from the caller:
127 119
 //  - A full container ID, which will exact match a container in daemon's list
... ...
@@ -741,16 +730,7 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.
741 741
 	return nil
742 742
 }
743 743
 
744
-// FIXME: harmonize with NewGraph()
745
-func NewDaemon(config *Config, eng *engine.Engine, registryService *registry.Service) (*Daemon, error) {
746
-	daemon, err := NewDaemonFromDirectory(config, eng, registryService)
747
-	if err != nil {
748
-		return nil, err
749
-	}
750
-	return daemon, nil
751
-}
752
-
753
-func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService *registry.Service) (*Daemon, error) {
744
+func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemon, err error) {
754 745
 	if config.Mtu == 0 {
755 746
 		config.Mtu = getDefaultNetworkMtu()
756 747
 	}
... ...
@@ -766,19 +746,6 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
766 766
 	}
767 767
 	config.DisableNetwork = config.Bridge.Iface == disableNetworkBridge
768 768
 
769
-	// Claim the pidfile first, to avoid any and all unexpected race conditions.
770
-	// Some of the init doesn't need a pidfile lock - but let's not try to be smart.
771
-	if config.Pidfile != "" {
772
-		file, err := pidfile.New(config.Pidfile)
773
-		if err != nil {
774
-			return nil, err
775
-		}
776
-		eng.OnShutdown(func() {
777
-			// Always release the pidfile last, just in case
778
-			file.Remove()
779
-		})
780
-	}
781
-
782 769
 	// Check that the system is supported and we have sufficient privileges
783 770
 	if runtime.GOOS != "linux" {
784 771
 		return nil, fmt.Errorf("The Docker daemon is only supported on linux")
... ...
@@ -826,17 +793,22 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
826 826
 		return nil, fmt.Errorf("error initializing graphdriver: %v", err)
827 827
 	}
828 828
 	logrus.Debugf("Using graph driver %s", driver)
829
-	// register cleanup for graph driver
830
-	eng.OnShutdown(func() {
831
-		if err := driver.Cleanup(); err != nil {
832
-			logrus.Errorf("Error during graph storage driver.Cleanup(): %v", err)
829
+
830
+	d := &Daemon{}
831
+	d.driver = driver
832
+
833
+	defer func() {
834
+		if err != nil {
835
+			if err := d.Shutdown(); err != nil {
836
+				logrus.Error(err)
837
+			}
833 838
 		}
834
-	})
839
+	}()
835 840
 
836 841
 	if config.EnableSelinuxSupport {
837 842
 		if selinuxEnabled() {
838 843
 			// As Docker on btrfs and SELinux are incompatible at present, error on both being enabled
839
-			if driver.String() == "btrfs" {
844
+			if d.driver.String() == "btrfs" {
840 845
 				return nil, fmt.Errorf("SELinux is not supported with the BTRFS graph driver")
841 846
 			}
842 847
 			logrus.Debug("SELinux enabled successfully")
... ...
@@ -854,12 +826,12 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
854 854
 	}
855 855
 
856 856
 	// Migrate the container if it is aufs and aufs is enabled
857
-	if err = migrateIfAufs(driver, config.Root); err != nil {
857
+	if err := migrateIfAufs(d.driver, config.Root); err != nil {
858 858
 		return nil, err
859 859
 	}
860 860
 
861 861
 	logrus.Debug("Creating images graph")
862
-	g, err := graph.NewGraph(path.Join(config.Root, "graph"), driver)
862
+	g, err := graph.NewGraph(path.Join(config.Root, "graph"), d.driver)
863 863
 	if err != nil {
864 864
 		return nil, err
865 865
 	}
... ...
@@ -897,7 +869,7 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
897 897
 		Events:   eventsService,
898 898
 		Trust:    trustService,
899 899
 	}
900
-	repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), tagCfg)
900
+	repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+d.driver.String()), tagCfg)
901 901
 	if err != nil {
902 902
 		return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
903 903
 	}
... ...
@@ -913,12 +885,8 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
913 913
 	if err != nil {
914 914
 		return nil, err
915 915
 	}
916
-	// register graph close on shutdown
917
-	eng.OnShutdown(func() {
918
-		if err := graph.Close(); err != nil {
919
-			logrus.Errorf("Error during container graph.Close(): %v", err)
920
-		}
921
-	})
916
+
917
+	d.containerGraph = graph
922 918
 
923 919
 	localCopy := path.Join(config.Root, "init", fmt.Sprintf("dockerinit-%s", dockerversion.VERSION))
924 920
 	sysInitPath := utils.DockerInitPath(localCopy)
... ...
@@ -947,66 +915,67 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
947 947
 		return nil, err
948 948
 	}
949 949
 
950
-	daemon := &Daemon{
951
-		ID:               trustKey.PublicKey().KeyID(),
952
-		repository:       daemonRepo,
953
-		containers:       &contStore{s: make(map[string]*Container)},
954
-		execCommands:     newExecStore(),
955
-		graph:            g,
956
-		repositories:     repositories,
957
-		idIndex:          truncindex.NewTruncIndex([]string{}),
958
-		sysInfo:          sysInfo,
959
-		volumes:          volumes,
960
-		config:           config,
961
-		containerGraph:   graph,
962
-		driver:           driver,
963
-		sysInitPath:      sysInitPath,
964
-		execDriver:       ed,
965
-		eng:              eng,
966
-		statsCollector:   newStatsCollector(1 * time.Second),
967
-		defaultLogConfig: config.LogConfig,
968
-		RegistryService:  registryService,
969
-		EventsService:    eventsService,
970
-	}
971
-
972
-	eng.OnShutdown(func() {
973
-		if err := daemon.shutdown(); err != nil {
974
-			logrus.Errorf("Error during daemon.shutdown(): %v", err)
975
-		}
976
-	})
977
-
978
-	if err := daemon.restore(); err != nil {
950
+	d.ID = trustKey.PublicKey().KeyID()
951
+	d.repository = daemonRepo
952
+	d.containers = &contStore{s: make(map[string]*Container)}
953
+	d.execCommands = newExecStore()
954
+	d.graph = g
955
+	d.repositories = repositories
956
+	d.idIndex = truncindex.NewTruncIndex([]string{})
957
+	d.sysInfo = sysInfo
958
+	d.volumes = volumes
959
+	d.config = config
960
+	d.sysInitPath = sysInitPath
961
+	d.execDriver = ed
962
+	d.statsCollector = newStatsCollector(1 * time.Second)
963
+	d.defaultLogConfig = config.LogConfig
964
+	d.RegistryService = registryService
965
+	d.EventsService = eventsService
966
+
967
+	if err := d.restore(); err != nil {
979 968
 		return nil, err
980 969
 	}
981 970
 
982 971
 	// set up filesystem watch on resolv.conf for network changes
983
-	if err := daemon.setupResolvconfWatcher(); err != nil {
972
+	if err := d.setupResolvconfWatcher(); err != nil {
984 973
 		return nil, err
985 974
 	}
986 975
 
987
-	return daemon, nil
976
+	return d, nil
988 977
 }
989 978
 
990
-func (daemon *Daemon) shutdown() error {
991
-	group := sync.WaitGroup{}
992
-	logrus.Debug("starting clean shutdown of all containers...")
993
-	for _, container := range daemon.List() {
994
-		c := container
995
-		if c.IsRunning() {
996
-			logrus.Debugf("stopping %s", c.ID)
997
-			group.Add(1)
998
-
999
-			go func() {
1000
-				defer group.Done()
1001
-				if err := c.KillSig(15); err != nil {
1002
-					logrus.Debugf("kill 15 error for %s - %s", c.ID, err)
1003
-				}
1004
-				c.WaitStop(-1 * time.Second)
1005
-				logrus.Debugf("container stopped %s", c.ID)
1006
-			}()
979
+func (daemon *Daemon) Shutdown() error {
980
+	if daemon.containerGraph != nil {
981
+		if err := daemon.containerGraph.Close(); err != nil {
982
+			logrus.Errorf("Error during container graph.Close(): %v", err)
1007 983
 		}
1008 984
 	}
1009
-	group.Wait()
985
+	if daemon.driver != nil {
986
+		if err := daemon.driver.Cleanup(); err != nil {
987
+			logrus.Errorf("Error during graph storage driver.Cleanup(): %v", err)
988
+		}
989
+	}
990
+	if daemon.containers != nil {
991
+		group := sync.WaitGroup{}
992
+		logrus.Debug("starting clean shutdown of all containers...")
993
+		for _, container := range daemon.List() {
994
+			c := container
995
+			if c.IsRunning() {
996
+				logrus.Debugf("stopping %s", c.ID)
997
+				group.Add(1)
998
+
999
+				go func() {
1000
+					defer group.Done()
1001
+					if err := c.KillSig(15); err != nil {
1002
+						logrus.Debugf("kill 15 error for %s - %s", c.ID, err)
1003
+					}
1004
+					c.WaitStop(-1 * time.Second)
1005
+					logrus.Debugf("container stopped %s", c.ID)
1006
+				}()
1007
+			}
1008
+		}
1009
+		group.Wait()
1010
+	}
1010 1011
 
1011 1012
 	return nil
1012 1013
 }
... ...
@@ -1087,26 +1056,6 @@ func (daemon *Daemon) UnsubscribeToContainerStats(name string, ch chan interface
1087 1087
 	return nil
1088 1088
 }
1089 1089
 
1090
-// Nuke kills all containers then removes all content
1091
-// from the content root, including images, volumes and
1092
-// container filesystems.
1093
-// Again: this will remove your entire docker daemon!
1094
-// FIXME: this is deprecated, and only used in legacy
1095
-// tests. Please remove.
1096
-func (daemon *Daemon) Nuke() error {
1097
-	var wg sync.WaitGroup
1098
-	for _, container := range daemon.List() {
1099
-		wg.Add(1)
1100
-		go func(c *Container) {
1101
-			c.Kill()
1102
-			wg.Done()
1103
-		}(container)
1104
-	}
1105
-	wg.Wait()
1106
-
1107
-	return os.RemoveAll(daemon.config.Root)
1108
-}
1109
-
1110 1090
 // FIXME: this is a convenience function for integration tests
1111 1091
 // which need direct access to daemon.graph.
1112 1092
 // Once the tests switch to using engine and jobs, this method
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"io"
8 8
 	"os"
9 9
 	"path/filepath"
10
+	"time"
10 11
 
11 12
 	"github.com/Sirupsen/logrus"
12 13
 	apiserver "github.com/docker/docker/api/server"
... ...
@@ -14,9 +15,9 @@ import (
14 14
 	"github.com/docker/docker/daemon"
15 15
 	_ "github.com/docker/docker/daemon/execdriver/lxc"
16 16
 	_ "github.com/docker/docker/daemon/execdriver/native"
17
-	"github.com/docker/docker/engine"
18 17
 	"github.com/docker/docker/pkg/homedir"
19 18
 	flag "github.com/docker/docker/pkg/mflag"
19
+	"github.com/docker/docker/pkg/pidfile"
20 20
 	"github.com/docker/docker/pkg/signal"
21 21
 	"github.com/docker/docker/pkg/system"
22 22
 	"github.com/docker/docker/pkg/timeutils"
... ...
@@ -83,14 +84,45 @@ func mainDaemon() {
83 83
 
84 84
 	logrus.SetFormatter(&logrus.TextFormatter{TimestampFormat: timeutils.RFC3339NanoFixed})
85 85
 
86
-	eng := engine.New()
87
-	signal.Trap(eng.Shutdown)
86
+	var pfile *pidfile.PidFile
87
+	if daemonCfg.Pidfile != "" {
88
+		pf, err := pidfile.New(daemonCfg.Pidfile)
89
+		if err != nil {
90
+			logrus.Fatalf("Error starting daemon: %v", err)
91
+		}
92
+		pfile = pf
93
+		defer func() {
94
+			if err := pfile.Remove(); err != nil {
95
+				logrus.Error(err)
96
+			}
97
+		}()
98
+	}
88 99
 
89 100
 	if err := migrateKey(); err != nil {
90 101
 		logrus.Fatal(err)
91 102
 	}
92 103
 	daemonCfg.TrustKeyPath = *flTrustKey
93 104
 
105
+	registryService := registry.NewService(registryCfg)
106
+	d, err := daemon.NewDaemon(daemonCfg, registryService)
107
+	if err != nil {
108
+		if pfile != nil {
109
+			if err := pfile.Remove(); err != nil {
110
+				logrus.Error(err)
111
+			}
112
+		}
113
+		logrus.Fatalf("Error starting daemon: %v", err)
114
+	}
115
+
116
+	logrus.Info("Daemon has completed initialization")
117
+
118
+	logrus.WithFields(logrus.Fields{
119
+		"version":     dockerversion.VERSION,
120
+		"commit":      dockerversion.GITCOMMIT,
121
+		"execdriver":  d.ExecutionDriver().Name(),
122
+		"graphdriver": d.GraphDriver().String(),
123
+	}).Info("Docker daemon")
124
+
94 125
 	serverConfig := &apiserver.ServerConfig{
95 126
 		Logging:     true,
96 127
 		EnableCors:  daemonCfg.EnableCors,
... ...
@@ -104,7 +136,7 @@ func mainDaemon() {
104 104
 		TlsKey:      *flKey,
105 105
 	}
106 106
 
107
-	api := apiserver.New(serverConfig, eng)
107
+	api := apiserver.New(serverConfig)
108 108
 
109 109
 	// The serve API routine never exits unless an error occurs
110 110
 	// We need to start it as a goroutine and wait on it so
... ...
@@ -119,40 +151,52 @@ func mainDaemon() {
119 119
 		serveAPIWait <- nil
120 120
 	}()
121 121
 
122
-	registryService := registry.NewService(registryCfg)
123
-	d, err := daemon.NewDaemon(daemonCfg, eng, registryService)
124
-	if err != nil {
125
-		eng.Shutdown()
126
-		logrus.Fatalf("Error starting daemon: %v", err)
127
-	}
128
-
129
-	if err := d.Install(eng); err != nil {
130
-		eng.Shutdown()
131
-		logrus.Fatalf("Error starting daemon: %v", err)
132
-	}
133
-
134
-	logrus.Info("Daemon has completed initialization")
135
-
136
-	logrus.WithFields(logrus.Fields{
137
-		"version":     dockerversion.VERSION,
138
-		"commit":      dockerversion.GITCOMMIT,
139
-		"execdriver":  d.ExecutionDriver().Name(),
140
-		"graphdriver": d.GraphDriver().String(),
141
-	}).Info("Docker daemon")
122
+	signal.Trap(func() {
123
+		api.Close()
124
+		<-serveAPIWait
125
+		shutdownDaemon(d, 15)
126
+		if pfile != nil {
127
+			if err := pfile.Remove(); err != nil {
128
+				logrus.Error(err)
129
+			}
130
+		}
131
+	})
142 132
 
143 133
 	// after the daemon is done setting up we can tell the api to start
144 134
 	// accepting connections with specified daemon
145 135
 	api.AcceptConnections(d)
146 136
 
147 137
 	// Daemon is fully initialized and handling API traffic
148
-	// Wait for serve API job to complete
138
+	// Wait for serve API to complete
149 139
 	errAPI := <-serveAPIWait
150
-	eng.Shutdown()
140
+	shutdownDaemon(d, 15)
151 141
 	if errAPI != nil {
142
+		if pfile != nil {
143
+			if err := pfile.Remove(); err != nil {
144
+				logrus.Error(err)
145
+			}
146
+		}
152 147
 		logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI)
153 148
 	}
154 149
 }
155 150
 
151
+// shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
152
+// d.Shutdown() is waiting too long to kill container or worst it's
153
+// blocked there
154
+func shutdownDaemon(d *daemon.Daemon, timeout time.Duration) {
155
+	ch := make(chan struct{})
156
+	go func() {
157
+		d.Shutdown()
158
+		close(ch)
159
+	}()
160
+	select {
161
+	case <-ch:
162
+		logrus.Debug("Clean shutdown succeded")
163
+	case <-time.After(timeout * time.Second):
164
+		logrus.Error("Force shutdown daemon")
165
+	}
166
+}
167
+
156 168
 // currentUserIsOwner checks whether the current user is the owner of the given
157 169
 // file.
158 170
 func currentUserIsOwner(f string) bool {
159 171
deleted file mode 100644
... ...
@@ -1,255 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"bufio"
5
-	"fmt"
6
-	"io"
7
-	"os"
8
-	"sort"
9
-	"strings"
10
-	"sync"
11
-	"time"
12
-
13
-	"github.com/docker/docker/pkg/ioutils"
14
-	"github.com/docker/docker/pkg/stringid"
15
-)
16
-
17
-// Installer is a standard interface for objects which can "install" themselves
18
-// on an engine by registering handlers.
19
-// This can be used as an entrypoint for external plugins etc.
20
-type Installer interface {
21
-	Install(*Engine) error
22
-}
23
-
24
-type Handler func(*Job) error
25
-
26
-var globalHandlers map[string]Handler
27
-
28
-func init() {
29
-	globalHandlers = make(map[string]Handler)
30
-}
31
-
32
-func Register(name string, handler Handler) error {
33
-	_, exists := globalHandlers[name]
34
-	if exists {
35
-		return fmt.Errorf("Can't overwrite global handler for command %s", name)
36
-	}
37
-	globalHandlers[name] = handler
38
-	return nil
39
-}
40
-
41
-func unregister(name string) {
42
-	delete(globalHandlers, name)
43
-}
44
-
45
-// The Engine is the core of Docker.
46
-// It acts as a store for *containers*, and allows manipulation of these
47
-// containers by executing *jobs*.
48
-type Engine struct {
49
-	handlers     map[string]Handler
50
-	catchall     Handler
51
-	hack         Hack // data for temporary hackery (see hack.go)
52
-	id           string
53
-	Stdout       io.Writer
54
-	Stderr       io.Writer
55
-	Stdin        io.Reader
56
-	Logging      bool
57
-	tasks        sync.WaitGroup
58
-	l            sync.RWMutex // lock for shutdown
59
-	shutdownWait sync.WaitGroup
60
-	shutdown     bool
61
-	onShutdown   []func() // shutdown handlers
62
-}
63
-
64
-func (eng *Engine) Register(name string, handler Handler) error {
65
-	_, exists := eng.handlers[name]
66
-	if exists {
67
-		return fmt.Errorf("Can't overwrite handler for command %s", name)
68
-	}
69
-	eng.handlers[name] = handler
70
-	return nil
71
-}
72
-
73
-func (eng *Engine) RegisterCatchall(catchall Handler) {
74
-	eng.catchall = catchall
75
-}
76
-
77
-// New initializes a new engine.
78
-func New() *Engine {
79
-	eng := &Engine{
80
-		handlers: make(map[string]Handler),
81
-		id:       stringid.GenerateRandomID(),
82
-		Stdout:   os.Stdout,
83
-		Stderr:   os.Stderr,
84
-		Stdin:    os.Stdin,
85
-		Logging:  true,
86
-	}
87
-	eng.Register("commands", func(job *Job) error {
88
-		for _, name := range eng.commands() {
89
-			job.Printf("%s\n", name)
90
-		}
91
-		return nil
92
-	})
93
-	// Copy existing global handlers
94
-	for k, v := range globalHandlers {
95
-		eng.handlers[k] = v
96
-	}
97
-	return eng
98
-}
99
-
100
-func (eng *Engine) String() string {
101
-	return fmt.Sprintf("%s", eng.id[:8])
102
-}
103
-
104
-// Commands returns a list of all currently registered commands,
105
-// sorted alphabetically.
106
-func (eng *Engine) commands() []string {
107
-	names := make([]string, 0, len(eng.handlers))
108
-	for name := range eng.handlers {
109
-		names = append(names, name)
110
-	}
111
-	sort.Strings(names)
112
-	return names
113
-}
114
-
115
-// Job creates a new job which can later be executed.
116
-// This function mimics `Command` from the standard os/exec package.
117
-func (eng *Engine) Job(name string, args ...string) *Job {
118
-	job := &Job{
119
-		Eng:     eng,
120
-		Name:    name,
121
-		Args:    args,
122
-		Stdin:   NewInput(),
123
-		Stdout:  NewOutput(),
124
-		Stderr:  NewOutput(),
125
-		env:     &Env{},
126
-		closeIO: true,
127
-
128
-		cancelled: make(chan struct{}),
129
-	}
130
-	if eng.Logging {
131
-		job.Stderr.Add(ioutils.NopWriteCloser(eng.Stderr))
132
-	}
133
-
134
-	// Catchall is shadowed by specific Register.
135
-	if handler, exists := eng.handlers[name]; exists {
136
-		job.handler = handler
137
-	} else if eng.catchall != nil && name != "" {
138
-		// empty job names are illegal, catchall or not.
139
-		job.handler = eng.catchall
140
-	}
141
-	return job
142
-}
143
-
144
-// OnShutdown registers a new callback to be called by Shutdown.
145
-// This is typically used by services to perform cleanup.
146
-func (eng *Engine) OnShutdown(h func()) {
147
-	eng.l.Lock()
148
-	eng.onShutdown = append(eng.onShutdown, h)
149
-	eng.shutdownWait.Add(1)
150
-	eng.l.Unlock()
151
-}
152
-
153
-// Shutdown permanently shuts down eng as follows:
154
-// - It refuses all new jobs, permanently.
155
-// - It waits for all active jobs to complete (with no timeout)
156
-// - It calls all shutdown handlers concurrently (if any)
157
-// - It returns when all handlers complete, or after 15 seconds,
158
-//	whichever happens first.
159
-func (eng *Engine) Shutdown() {
160
-	eng.l.Lock()
161
-	if eng.shutdown {
162
-		eng.l.Unlock()
163
-		eng.shutdownWait.Wait()
164
-		return
165
-	}
166
-	eng.shutdown = true
167
-	eng.l.Unlock()
168
-	// We don't need to protect the rest with a lock, to allow
169
-	// for other calls to immediately fail with "shutdown" instead
170
-	// of hanging for 15 seconds.
171
-	// This requires all concurrent calls to check for shutdown, otherwise
172
-	// it might cause a race.
173
-
174
-	// Wait for all jobs to complete.
175
-	// Timeout after 5 seconds.
176
-	tasksDone := make(chan struct{})
177
-	go func() {
178
-		eng.tasks.Wait()
179
-		close(tasksDone)
180
-	}()
181
-	select {
182
-	case <-time.After(time.Second * 5):
183
-	case <-tasksDone:
184
-	}
185
-
186
-	// Call shutdown handlers, if any.
187
-	// Timeout after 10 seconds.
188
-	for _, h := range eng.onShutdown {
189
-		go func(h func()) {
190
-			h()
191
-			eng.shutdownWait.Done()
192
-		}(h)
193
-	}
194
-	done := make(chan struct{})
195
-	go func() {
196
-		eng.shutdownWait.Wait()
197
-		close(done)
198
-	}()
199
-	select {
200
-	case <-time.After(time.Second * 10):
201
-	case <-done:
202
-	}
203
-	return
204
-}
205
-
206
-// IsShutdown returns true if the engine is in the process
207
-// of shutting down, or already shut down.
208
-// Otherwise it returns false.
209
-func (eng *Engine) IsShutdown() bool {
210
-	eng.l.RLock()
211
-	defer eng.l.RUnlock()
212
-	return eng.shutdown
213
-}
214
-
215
-// ParseJob creates a new job from a text description using a shell-like syntax.
216
-//
217
-// The following syntax is used to parse `input`:
218
-//
219
-// * Words are separated using standard whitespaces as separators.
220
-// * Quotes and backslashes are not interpreted.
221
-// * Words of the form 'KEY=[VALUE]' are added to the job environment.
222
-// * All other words are added to the job arguments.
223
-//
224
-// For example:
225
-//
226
-// job, _ := eng.ParseJob("VERBOSE=1 echo hello TEST=true world")
227
-//
228
-// The resulting job will have:
229
-//	job.Args={"echo", "hello", "world"}
230
-//	job.Env={"VERBOSE":"1", "TEST":"true"}
231
-//
232
-func (eng *Engine) ParseJob(input string) (*Job, error) {
233
-	// FIXME: use a full-featured command parser
234
-	scanner := bufio.NewScanner(strings.NewReader(input))
235
-	scanner.Split(bufio.ScanWords)
236
-	var (
237
-		cmd []string
238
-		env Env
239
-	)
240
-	for scanner.Scan() {
241
-		word := scanner.Text()
242
-		kv := strings.SplitN(word, "=", 2)
243
-		if len(kv) == 2 {
244
-			env.Set(kv[0], kv[1])
245
-		} else {
246
-			cmd = append(cmd, word)
247
-		}
248
-	}
249
-	if len(cmd) == 0 {
250
-		return nil, fmt.Errorf("empty command: '%s'", input)
251
-	}
252
-	job := eng.Job(cmd[0], cmd[1:]...)
253
-	job.Env().Init(&env)
254
-	return job, nil
255
-}
256 1
deleted file mode 100644
... ...
@@ -1,236 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"bytes"
5
-	"strings"
6
-	"testing"
7
-
8
-	"github.com/docker/docker/pkg/ioutils"
9
-)
10
-
11
-func TestRegister(t *testing.T) {
12
-	if err := Register("dummy1", nil); err != nil {
13
-		t.Fatal(err)
14
-	}
15
-
16
-	if err := Register("dummy1", nil); err == nil {
17
-		t.Fatalf("Expecting error, got none")
18
-	}
19
-	// Register is global so let's cleanup to avoid conflicts
20
-	defer unregister("dummy1")
21
-
22
-	eng := New()
23
-
24
-	//Should fail because global handlers are copied
25
-	//at the engine creation
26
-	if err := eng.Register("dummy1", nil); err == nil {
27
-		t.Fatalf("Expecting error, got none")
28
-	}
29
-
30
-	if err := eng.Register("dummy2", nil); err != nil {
31
-		t.Fatal(err)
32
-	}
33
-
34
-	if err := eng.Register("dummy2", nil); err == nil {
35
-		t.Fatalf("Expecting error, got none")
36
-	}
37
-	defer unregister("dummy2")
38
-}
39
-
40
-func TestJob(t *testing.T) {
41
-	eng := New()
42
-	job1 := eng.Job("dummy1", "--level=awesome")
43
-
44
-	if job1.handler != nil {
45
-		t.Fatalf("job1.handler should be empty")
46
-	}
47
-
48
-	h := func(j *Job) error {
49
-		j.Printf("%s\n", j.Name)
50
-		return nil
51
-	}
52
-
53
-	eng.Register("dummy2", h)
54
-	defer unregister("dummy2")
55
-	job2 := eng.Job("dummy2", "--level=awesome")
56
-
57
-	if job2.handler == nil {
58
-		t.Fatalf("job2.handler shouldn't be nil")
59
-	}
60
-
61
-	if job2.handler(job2) != nil {
62
-		t.Fatalf("handler dummy2 was not found in job2")
63
-	}
64
-}
65
-
66
-func TestEngineShutdown(t *testing.T) {
67
-	eng := New()
68
-	if eng.IsShutdown() {
69
-		t.Fatalf("Engine should not show as shutdown")
70
-	}
71
-	eng.Shutdown()
72
-	if !eng.IsShutdown() {
73
-		t.Fatalf("Engine should show as shutdown")
74
-	}
75
-}
76
-
77
-func TestEngineCommands(t *testing.T) {
78
-	eng := New()
79
-	handler := func(job *Job) error { return nil }
80
-	eng.Register("foo", handler)
81
-	eng.Register("bar", handler)
82
-	eng.Register("echo", handler)
83
-	eng.Register("die", handler)
84
-	var output bytes.Buffer
85
-	commands := eng.Job("commands")
86
-	commands.Stdout.Add(&output)
87
-	commands.Run()
88
-	expected := "bar\ncommands\ndie\necho\nfoo\n"
89
-	if result := output.String(); result != expected {
90
-		t.Fatalf("Unexpected output:\nExpected = %v\nResult   = %v\n", expected, result)
91
-	}
92
-}
93
-
94
-func TestEngineString(t *testing.T) {
95
-	eng1 := New()
96
-	eng2 := New()
97
-	s1 := eng1.String()
98
-	s2 := eng2.String()
99
-	if eng1 == eng2 {
100
-		t.Fatalf("Different engines should have different names (%v == %v)", s1, s2)
101
-	}
102
-}
103
-
104
-func TestParseJob(t *testing.T) {
105
-	eng := New()
106
-	// Verify that the resulting job calls to the right place
107
-	var called bool
108
-	eng.Register("echo", func(job *Job) error {
109
-		called = true
110
-		return nil
111
-	})
112
-	input := "echo DEBUG=1 hello world VERBOSITY=42"
113
-	job, err := eng.ParseJob(input)
114
-	if err != nil {
115
-		t.Fatal(err)
116
-	}
117
-	if job.Name != "echo" {
118
-		t.Fatalf("Invalid job name: %v", job.Name)
119
-	}
120
-	if strings.Join(job.Args, ":::") != "hello:::world" {
121
-		t.Fatalf("Invalid job args: %v", job.Args)
122
-	}
123
-	if job.Env().Get("DEBUG") != "1" {
124
-		t.Fatalf("Invalid job env: %v", job.Env)
125
-	}
126
-	if job.Env().Get("VERBOSITY") != "42" {
127
-		t.Fatalf("Invalid job env: %v", job.Env)
128
-	}
129
-	if len(job.Env().Map()) != 2 {
130
-		t.Fatalf("Invalid job env: %v", job.Env)
131
-	}
132
-	if err := job.Run(); err != nil {
133
-		t.Fatal(err)
134
-	}
135
-	if !called {
136
-		t.Fatalf("Job was not called")
137
-	}
138
-}
139
-
140
-func TestCatchallEmptyName(t *testing.T) {
141
-	eng := New()
142
-	var called bool
143
-	eng.RegisterCatchall(func(job *Job) error {
144
-		called = true
145
-		return nil
146
-	})
147
-	err := eng.Job("").Run()
148
-	if err == nil {
149
-		t.Fatalf("Engine.Job(\"\").Run() should return an error")
150
-	}
151
-	if called {
152
-		t.Fatalf("Engine.Job(\"\").Run() should return an error")
153
-	}
154
-}
155
-
156
-// Ensure that a job within a job both using the same underlying standard
157
-// output writer does not close the output of the outer job when the inner
158
-// job's stdout is wrapped with a NopCloser. When not wrapped, it should
159
-// close the outer job's output.
160
-func TestNestedJobSharedOutput(t *testing.T) {
161
-	var (
162
-		outerHandler Handler
163
-		innerHandler Handler
164
-		wrapOutput   bool
165
-	)
166
-
167
-	outerHandler = func(job *Job) error {
168
-		job.Stdout.Write([]byte("outer1"))
169
-
170
-		innerJob := job.Eng.Job("innerJob")
171
-
172
-		if wrapOutput {
173
-			innerJob.Stdout.Add(ioutils.NopWriteCloser(job.Stdout))
174
-		} else {
175
-			innerJob.Stdout.Add(job.Stdout)
176
-		}
177
-
178
-		if err := innerJob.Run(); err != nil {
179
-			t.Fatal(err)
180
-		}
181
-
182
-		// If wrapOutput was *false* this write will do nothing.
183
-		// FIXME (jlhawn): It should cause an error to write to
184
-		// closed output.
185
-		job.Stdout.Write([]byte(" outer2"))
186
-
187
-		return nil
188
-	}
189
-
190
-	innerHandler = func(job *Job) error {
191
-		job.Stdout.Write([]byte(" inner"))
192
-
193
-		return nil
194
-	}
195
-
196
-	eng := New()
197
-	eng.Register("outerJob", outerHandler)
198
-	eng.Register("innerJob", innerHandler)
199
-
200
-	// wrapOutput starts *false* so the expected
201
-	// output of running the outer job will be:
202
-	//
203
-	//     "outer1 inner"
204
-	//
205
-	outBuf := new(bytes.Buffer)
206
-	outerJob := eng.Job("outerJob")
207
-	outerJob.Stdout.Add(outBuf)
208
-
209
-	if err := outerJob.Run(); err != nil {
210
-		t.Fatal(err)
211
-	}
212
-
213
-	expectedOutput := "outer1 inner"
214
-	if outBuf.String() != expectedOutput {
215
-		t.Fatalf("expected job output to be %q, got %q", expectedOutput, outBuf.String())
216
-	}
217
-
218
-	// Set wrapOutput to true so that the expected
219
-	// output of running the outer job will be:
220
-	//
221
-	//     "outer1 inner outer2"
222
-	//
223
-	wrapOutput = true
224
-	outBuf.Reset()
225
-	outerJob = eng.Job("outerJob")
226
-	outerJob.Stdout.Add(outBuf)
227
-
228
-	if err := outerJob.Run(); err != nil {
229
-		t.Fatal(err)
230
-	}
231
-
232
-	expectedOutput = "outer1 inner outer2"
233
-	if outBuf.String() != expectedOutput {
234
-		t.Fatalf("expected job output to be %q, got %q", expectedOutput, outBuf.String())
235
-	}
236
-}
237 1
deleted file mode 100644
... ...
@@ -1,313 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"bytes"
5
-	"encoding/json"
6
-	"fmt"
7
-	"io"
8
-	"strconv"
9
-	"strings"
10
-	"time"
11
-
12
-	"github.com/docker/docker/pkg/ioutils"
13
-)
14
-
15
-type Env []string
16
-
17
-// Get returns the last value associated with the given key. If there are no
18
-// values associated with the key, Get returns the empty string.
19
-func (env *Env) Get(key string) (value string) {
20
-	// not using Map() because of the extra allocations https://github.com/docker/docker/pull/7488#issuecomment-51638315
21
-	for _, kv := range *env {
22
-		if strings.Index(kv, "=") == -1 {
23
-			continue
24
-		}
25
-		parts := strings.SplitN(kv, "=", 2)
26
-		if parts[0] != key {
27
-			continue
28
-		}
29
-		if len(parts) < 2 {
30
-			value = ""
31
-		} else {
32
-			value = parts[1]
33
-		}
34
-	}
35
-	return
36
-}
37
-
38
-func (env *Env) Exists(key string) bool {
39
-	_, exists := env.Map()[key]
40
-	return exists
41
-}
42
-
43
-// Len returns the number of keys in the environment.
44
-// Note that len(env) might be different from env.Len(),
45
-// because the same key might be set multiple times.
46
-func (env *Env) Len() int {
47
-	return len(env.Map())
48
-}
49
-
50
-func (env *Env) Init(src *Env) {
51
-	(*env) = make([]string, 0, len(*src))
52
-	for _, val := range *src {
53
-		(*env) = append((*env), val)
54
-	}
55
-}
56
-
57
-func (env *Env) GetBool(key string) (value bool) {
58
-	s := strings.ToLower(strings.Trim(env.Get(key), " \t"))
59
-	if s == "" || s == "0" || s == "no" || s == "false" || s == "none" {
60
-		return false
61
-	}
62
-	return true
63
-}
64
-
65
-func (env *Env) SetBool(key string, value bool) {
66
-	if value {
67
-		env.Set(key, "1")
68
-	} else {
69
-		env.Set(key, "0")
70
-	}
71
-}
72
-
73
-func (env *Env) GetTime(key string) (time.Time, error) {
74
-	t, err := time.Parse(time.RFC3339Nano, env.Get(key))
75
-	return t, err
76
-}
77
-
78
-func (env *Env) SetTime(key string, t time.Time) {
79
-	env.Set(key, t.Format(time.RFC3339Nano))
80
-}
81
-
82
-func (env *Env) GetInt(key string) int {
83
-	return int(env.GetInt64(key))
84
-}
85
-
86
-func (env *Env) GetInt64(key string) int64 {
87
-	s := strings.Trim(env.Get(key), " \t")
88
-	val, err := strconv.ParseInt(s, 10, 64)
89
-	if err != nil {
90
-		return 0
91
-	}
92
-	return val
93
-}
94
-
95
-func (env *Env) SetInt(key string, value int) {
96
-	env.Set(key, fmt.Sprintf("%d", value))
97
-}
98
-
99
-func (env *Env) SetInt64(key string, value int64) {
100
-	env.Set(key, fmt.Sprintf("%d", value))
101
-}
102
-
103
-// Returns nil if key not found
104
-func (env *Env) GetList(key string) []string {
105
-	sval := env.Get(key)
106
-	if sval == "" {
107
-		return nil
108
-	}
109
-	l := make([]string, 0, 1)
110
-	if err := json.Unmarshal([]byte(sval), &l); err != nil {
111
-		l = append(l, sval)
112
-	}
113
-	return l
114
-}
115
-
116
-func (env *Env) GetSubEnv(key string) *Env {
117
-	sval := env.Get(key)
118
-	if sval == "" {
119
-		return nil
120
-	}
121
-	buf := bytes.NewBufferString(sval)
122
-	var sub Env
123
-	if err := sub.Decode(buf); err != nil {
124
-		return nil
125
-	}
126
-	return &sub
127
-}
128
-
129
-func (env *Env) SetSubEnv(key string, sub *Env) error {
130
-	var buf bytes.Buffer
131
-	if err := sub.Encode(&buf); err != nil {
132
-		return err
133
-	}
134
-	env.Set(key, string(buf.Bytes()))
135
-	return nil
136
-}
137
-
138
-func (env *Env) GetJson(key string, iface interface{}) error {
139
-	sval := env.Get(key)
140
-	if sval == "" {
141
-		return nil
142
-	}
143
-	return json.Unmarshal([]byte(sval), iface)
144
-}
145
-
146
-func (env *Env) SetJson(key string, value interface{}) error {
147
-	sval, err := json.Marshal(value)
148
-	if err != nil {
149
-		return err
150
-	}
151
-	env.Set(key, string(sval))
152
-	return nil
153
-}
154
-
155
-func (env *Env) SetList(key string, value []string) error {
156
-	return env.SetJson(key, value)
157
-}
158
-
159
-func (env *Env) Set(key, value string) {
160
-	*env = append(*env, key+"="+value)
161
-}
162
-
163
-func NewDecoder(src io.Reader) *Decoder {
164
-	return &Decoder{
165
-		json.NewDecoder(src),
166
-	}
167
-}
168
-
169
-type Decoder struct {
170
-	*json.Decoder
171
-}
172
-
173
-func (decoder *Decoder) Decode() (*Env, error) {
174
-	m := make(map[string]interface{})
175
-	if err := decoder.Decoder.Decode(&m); err != nil {
176
-		return nil, err
177
-	}
178
-	env := &Env{}
179
-	for key, value := range m {
180
-		env.SetAuto(key, value)
181
-	}
182
-	return env, nil
183
-}
184
-
185
-// DecodeEnv decodes `src` as a json dictionary, and adds
186
-// each decoded key-value pair to the environment.
187
-//
188
-// If `src` cannot be decoded as a json dictionary, an error
189
-// is returned.
190
-func (env *Env) Decode(src io.Reader) error {
191
-	m := make(map[string]interface{})
192
-	d := json.NewDecoder(src)
193
-	// We need this or we'll lose data when we decode int64 in json
194
-	d.UseNumber()
195
-	if err := d.Decode(&m); err != nil {
196
-		return err
197
-	}
198
-	for k, v := range m {
199
-		env.SetAuto(k, v)
200
-	}
201
-	return nil
202
-}
203
-
204
-func (env *Env) SetAuto(k string, v interface{}) {
205
-	// Issue 7941 - if the value in the incoming JSON is null then treat it
206
-	// as if they never specified the property at all.
207
-	if v == nil {
208
-		return
209
-	}
210
-
211
-	// FIXME: we fix-convert float values to int, because
212
-	// encoding/json decodes integers to float64, but cannot encode them back.
213
-	// (See https://golang.org/src/pkg/encoding/json/decode.go#L46)
214
-	if fval, ok := v.(float64); ok {
215
-		env.SetInt64(k, int64(fval))
216
-	} else if sval, ok := v.(string); ok {
217
-		env.Set(k, sval)
218
-	} else if val, err := json.Marshal(v); err == nil {
219
-		env.Set(k, string(val))
220
-	} else {
221
-		env.Set(k, fmt.Sprintf("%v", v))
222
-	}
223
-}
224
-
225
-func changeFloats(v interface{}) interface{} {
226
-	switch v := v.(type) {
227
-	case float64:
228
-		return int(v)
229
-	case map[string]interface{}:
230
-		for key, val := range v {
231
-			v[key] = changeFloats(val)
232
-		}
233
-	case []interface{}:
234
-		for idx, val := range v {
235
-			v[idx] = changeFloats(val)
236
-		}
237
-	}
238
-	return v
239
-}
240
-
241
-func (env *Env) Encode(dst io.Writer) error {
242
-	m := make(map[string]interface{})
243
-	for k, v := range env.Map() {
244
-		var val interface{}
245
-		if err := json.Unmarshal([]byte(v), &val); err == nil {
246
-			// FIXME: we fix-convert float values to int, because
247
-			// encoding/json decodes integers to float64, but cannot encode them back.
248
-			// (See https://golang.org/src/pkg/encoding/json/decode.go#L46)
249
-			m[k] = changeFloats(val)
250
-		} else {
251
-			m[k] = v
252
-		}
253
-	}
254
-	if err := json.NewEncoder(dst).Encode(&m); err != nil {
255
-		return err
256
-	}
257
-	return nil
258
-}
259
-
260
-func (env *Env) WriteTo(dst io.Writer) (int64, error) {
261
-	wc := ioutils.NewWriteCounter(dst)
262
-	err := env.Encode(wc)
263
-	return wc.Count, err
264
-}
265
-
266
-func (env *Env) Import(src interface{}) (err error) {
267
-	defer func() {
268
-		if err != nil {
269
-			err = fmt.Errorf("ImportEnv: %s", err)
270
-		}
271
-	}()
272
-	var buf bytes.Buffer
273
-	if err := json.NewEncoder(&buf).Encode(src); err != nil {
274
-		return err
275
-	}
276
-	if err := env.Decode(&buf); err != nil {
277
-		return err
278
-	}
279
-	return nil
280
-}
281
-
282
-func (env *Env) Map() map[string]string {
283
-	m := make(map[string]string)
284
-	for _, kv := range *env {
285
-		parts := strings.SplitN(kv, "=", 2)
286
-		m[parts[0]] = parts[1]
287
-	}
288
-	return m
289
-}
290
-
291
-// MultiMap returns a representation of env as a
292
-// map of string arrays, keyed by string.
293
-// This is the same structure as http headers for example,
294
-// which allow each key to have multiple values.
295
-func (env *Env) MultiMap() map[string][]string {
296
-	m := make(map[string][]string)
297
-	for _, kv := range *env {
298
-		parts := strings.SplitN(kv, "=", 2)
299
-		m[parts[0]] = append(m[parts[0]], parts[1])
300
-	}
301
-	return m
302
-}
303
-
304
-// InitMultiMap removes all values in env, then initializes
305
-// new values from the contents of m.
306
-func (env *Env) InitMultiMap(m map[string][]string) {
307
-	(*env) = make([]string, 0, len(m))
308
-	for k, vals := range m {
309
-		for _, v := range vals {
310
-			env.Set(k, v)
311
-		}
312
-	}
313
-}
314 1
deleted file mode 100644
... ...
@@ -1,366 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"bytes"
5
-	"encoding/json"
6
-	"testing"
7
-	"time"
8
-
9
-	"github.com/docker/docker/pkg/stringutils"
10
-)
11
-
12
-func TestEnvLenZero(t *testing.T) {
13
-	env := &Env{}
14
-	if env.Len() != 0 {
15
-		t.Fatalf("%d", env.Len())
16
-	}
17
-}
18
-
19
-func TestEnvLenNotZero(t *testing.T) {
20
-	env := &Env{}
21
-	env.Set("foo", "bar")
22
-	env.Set("ga", "bu")
23
-	if env.Len() != 2 {
24
-		t.Fatalf("%d", env.Len())
25
-	}
26
-}
27
-
28
-func TestEnvLenDup(t *testing.T) {
29
-	env := &Env{
30
-		"foo=bar",
31
-		"foo=baz",
32
-		"a=b",
33
-	}
34
-	// len(env) != env.Len()
35
-	if env.Len() != 2 {
36
-		t.Fatalf("%d", env.Len())
37
-	}
38
-}
39
-
40
-func TestEnvGetDup(t *testing.T) {
41
-	env := &Env{
42
-		"foo=bar",
43
-		"foo=baz",
44
-		"foo=bif",
45
-	}
46
-	expected := "bif"
47
-	if v := env.Get("foo"); v != expected {
48
-		t.Fatalf("expect %q, got %q", expected, v)
49
-	}
50
-}
51
-
52
-func TestNewJob(t *testing.T) {
53
-	job := mkJob(t, "dummy", "--level=awesome")
54
-	if job.Name != "dummy" {
55
-		t.Fatalf("Wrong job name: %s", job.Name)
56
-	}
57
-	if len(job.Args) != 1 {
58
-		t.Fatalf("Wrong number of job arguments: %d", len(job.Args))
59
-	}
60
-	if job.Args[0] != "--level=awesome" {
61
-		t.Fatalf("Wrong job arguments: %s", job.Args[0])
62
-	}
63
-}
64
-
65
-func TestSetenv(t *testing.T) {
66
-	job := mkJob(t, "dummy")
67
-	job.Setenv("foo", "bar")
68
-	if val := job.Getenv("foo"); val != "bar" {
69
-		t.Fatalf("Getenv returns incorrect value: %s", val)
70
-	}
71
-
72
-	job.Setenv("bar", "")
73
-	if val := job.Getenv("bar"); val != "" {
74
-		t.Fatalf("Getenv returns incorrect value: %s", val)
75
-	}
76
-	if val := job.Getenv("nonexistent"); val != "" {
77
-		t.Fatalf("Getenv returns incorrect value: %s", val)
78
-	}
79
-}
80
-
81
-func TestDecodeEnv(t *testing.T) {
82
-	job := mkJob(t, "dummy")
83
-	type tmp struct {
84
-		Id1 int64
85
-		Id2 int64
86
-	}
87
-	body := []byte("{\"tags\":{\"Id1\":123, \"Id2\":1234567}}")
88
-	if err := job.DecodeEnv(bytes.NewBuffer(body)); err != nil {
89
-		t.Fatalf("DecodeEnv failed: %v", err)
90
-	}
91
-	mytag := tmp{}
92
-	if val := job.GetenvJson("tags", &mytag); val != nil {
93
-		t.Fatalf("GetenvJson returns incorrect value: %s", val)
94
-	}
95
-
96
-	if mytag.Id1 != 123 || mytag.Id2 != 1234567 {
97
-		t.Fatal("Get wrong values set by job.DecodeEnv")
98
-	}
99
-}
100
-
101
-func TestSetenvBool(t *testing.T) {
102
-	job := mkJob(t, "dummy")
103
-	job.SetenvBool("foo", true)
104
-	if val := job.GetenvBool("foo"); !val {
105
-		t.Fatalf("GetenvBool returns incorrect value: %t", val)
106
-	}
107
-
108
-	job.SetenvBool("bar", false)
109
-	if val := job.GetenvBool("bar"); val {
110
-		t.Fatalf("GetenvBool returns incorrect value: %t", val)
111
-	}
112
-
113
-	if val := job.GetenvBool("nonexistent"); val {
114
-		t.Fatalf("GetenvBool returns incorrect value: %t", val)
115
-	}
116
-}
117
-
118
-func TestSetenvTime(t *testing.T) {
119
-	job := mkJob(t, "dummy")
120
-
121
-	now := time.Now()
122
-	job.SetenvTime("foo", now)
123
-	if val, err := job.GetenvTime("foo"); err != nil {
124
-		t.Fatalf("GetenvTime failed to parse: %v", err)
125
-	} else {
126
-		nowStr := now.Format(time.RFC3339)
127
-		valStr := val.Format(time.RFC3339)
128
-		if nowStr != valStr {
129
-			t.Fatalf("GetenvTime returns incorrect value: %s, Expected: %s", valStr, nowStr)
130
-		}
131
-	}
132
-
133
-	job.Setenv("bar", "Obviously I'm not a date")
134
-	if val, err := job.GetenvTime("bar"); err == nil {
135
-		t.Fatalf("GetenvTime was supposed to fail, instead returned: %s", val)
136
-	}
137
-}
138
-
139
-func TestSetenvInt(t *testing.T) {
140
-	job := mkJob(t, "dummy")
141
-
142
-	job.SetenvInt("foo", -42)
143
-	if val := job.GetenvInt("foo"); val != -42 {
144
-		t.Fatalf("GetenvInt returns incorrect value: %d", val)
145
-	}
146
-
147
-	job.SetenvInt("bar", 42)
148
-	if val := job.GetenvInt("bar"); val != 42 {
149
-		t.Fatalf("GetenvInt returns incorrect value: %d", val)
150
-	}
151
-	if val := job.GetenvInt("nonexistent"); val != 0 {
152
-		t.Fatalf("GetenvInt returns incorrect value: %d", val)
153
-	}
154
-}
155
-
156
-func TestSetenvList(t *testing.T) {
157
-	job := mkJob(t, "dummy")
158
-
159
-	job.SetenvList("foo", []string{"bar"})
160
-	if val := job.GetenvList("foo"); len(val) != 1 || val[0] != "bar" {
161
-		t.Fatalf("GetenvList returns incorrect value: %v", val)
162
-	}
163
-
164
-	job.SetenvList("bar", nil)
165
-	if val := job.GetenvList("bar"); val != nil {
166
-		t.Fatalf("GetenvList returns incorrect value: %v", val)
167
-	}
168
-	if val := job.GetenvList("nonexistent"); val != nil {
169
-		t.Fatalf("GetenvList returns incorrect value: %v", val)
170
-	}
171
-}
172
-
173
-func TestEnviron(t *testing.T) {
174
-	job := mkJob(t, "dummy")
175
-	job.Setenv("foo", "bar")
176
-	val, exists := job.Environ()["foo"]
177
-	if !exists {
178
-		t.Fatalf("foo not found in the environ")
179
-	}
180
-	if val != "bar" {
181
-		t.Fatalf("bar not found in the environ")
182
-	}
183
-}
184
-
185
-func TestMultiMap(t *testing.T) {
186
-	e := &Env{}
187
-	e.Set("foo", "bar")
188
-	e.Set("bar", "baz")
189
-	e.Set("hello", "world")
190
-	m := e.MultiMap()
191
-	e2 := &Env{}
192
-	e2.Set("old_key", "something something something")
193
-	e2.InitMultiMap(m)
194
-	if v := e2.Get("old_key"); v != "" {
195
-		t.Fatalf("%#v", v)
196
-	}
197
-	if v := e2.Get("bar"); v != "baz" {
198
-		t.Fatalf("%#v", v)
199
-	}
200
-	if v := e2.Get("hello"); v != "world" {
201
-		t.Fatalf("%#v", v)
202
-	}
203
-}
204
-
205
-func testMap(l int) [][2]string {
206
-	res := make([][2]string, l)
207
-	for i := 0; i < l; i++ {
208
-		t := [2]string{stringutils.GenerateRandomAsciiString(5), stringutils.GenerateRandomAsciiString(20)}
209
-		res[i] = t
210
-	}
211
-	return res
212
-}
213
-
214
-func BenchmarkSet(b *testing.B) {
215
-	fix := testMap(100)
216
-	b.ResetTimer()
217
-	for i := 0; i < b.N; i++ {
218
-		env := &Env{}
219
-		for _, kv := range fix {
220
-			env.Set(kv[0], kv[1])
221
-		}
222
-	}
223
-}
224
-
225
-func BenchmarkSetJson(b *testing.B) {
226
-	fix := testMap(100)
227
-	type X struct {
228
-		f string
229
-	}
230
-	b.ResetTimer()
231
-	for i := 0; i < b.N; i++ {
232
-		env := &Env{}
233
-		for _, kv := range fix {
234
-			if err := env.SetJson(kv[0], X{kv[1]}); err != nil {
235
-				b.Fatal(err)
236
-			}
237
-		}
238
-	}
239
-}
240
-
241
-func BenchmarkGet(b *testing.B) {
242
-	fix := testMap(100)
243
-	env := &Env{}
244
-	for _, kv := range fix {
245
-		env.Set(kv[0], kv[1])
246
-	}
247
-	b.ResetTimer()
248
-	for i := 0; i < b.N; i++ {
249
-		for _, kv := range fix {
250
-			env.Get(kv[0])
251
-		}
252
-	}
253
-}
254
-
255
-func BenchmarkGetJson(b *testing.B) {
256
-	fix := testMap(100)
257
-	env := &Env{}
258
-	type X struct {
259
-		f string
260
-	}
261
-	for _, kv := range fix {
262
-		env.SetJson(kv[0], X{kv[1]})
263
-	}
264
-	b.ResetTimer()
265
-	for i := 0; i < b.N; i++ {
266
-		for _, kv := range fix {
267
-			if err := env.GetJson(kv[0], &X{}); err != nil {
268
-				b.Fatal(err)
269
-			}
270
-		}
271
-	}
272
-}
273
-
274
-func BenchmarkEncode(b *testing.B) {
275
-	fix := testMap(100)
276
-	env := &Env{}
277
-	type X struct {
278
-		f string
279
-	}
280
-	// half a json
281
-	for i, kv := range fix {
282
-		if i%2 != 0 {
283
-			if err := env.SetJson(kv[0], X{kv[1]}); err != nil {
284
-				b.Fatal(err)
285
-			}
286
-			continue
287
-		}
288
-		env.Set(kv[0], kv[1])
289
-	}
290
-	var writer bytes.Buffer
291
-	b.ResetTimer()
292
-	for i := 0; i < b.N; i++ {
293
-		env.Encode(&writer)
294
-		writer.Reset()
295
-	}
296
-}
297
-
298
-func BenchmarkDecode(b *testing.B) {
299
-	fix := testMap(100)
300
-	env := &Env{}
301
-	type X struct {
302
-		f string
303
-	}
304
-	// half a json
305
-	for i, kv := range fix {
306
-		if i%2 != 0 {
307
-			if err := env.SetJson(kv[0], X{kv[1]}); err != nil {
308
-				b.Fatal(err)
309
-			}
310
-			continue
311
-		}
312
-		env.Set(kv[0], kv[1])
313
-	}
314
-	var writer bytes.Buffer
315
-	env.Encode(&writer)
316
-	denv := &Env{}
317
-	reader := bytes.NewReader(writer.Bytes())
318
-	b.ResetTimer()
319
-	for i := 0; i < b.N; i++ {
320
-		err := denv.Decode(reader)
321
-		if err != nil {
322
-			b.Fatal(err)
323
-		}
324
-		reader.Seek(0, 0)
325
-	}
326
-}
327
-
328
-func TestLongNumbers(t *testing.T) {
329
-	type T struct {
330
-		TestNum int64
331
-	}
332
-	v := T{67108864}
333
-	var buf bytes.Buffer
334
-	e := &Env{}
335
-	e.SetJson("Test", v)
336
-	if err := e.Encode(&buf); err != nil {
337
-		t.Fatal(err)
338
-	}
339
-	res := make(map[string]T)
340
-	if err := json.Unmarshal(buf.Bytes(), &res); err != nil {
341
-		t.Fatal(err)
342
-	}
343
-	if res["Test"].TestNum != v.TestNum {
344
-		t.Fatalf("TestNum %d, expected %d", res["Test"].TestNum, v.TestNum)
345
-	}
346
-}
347
-
348
-func TestLongNumbersArray(t *testing.T) {
349
-	type T struct {
350
-		TestNum []int64
351
-	}
352
-	v := T{[]int64{67108864}}
353
-	var buf bytes.Buffer
354
-	e := &Env{}
355
-	e.SetJson("Test", v)
356
-	if err := e.Encode(&buf); err != nil {
357
-		t.Fatal(err)
358
-	}
359
-	res := make(map[string]T)
360
-	if err := json.Unmarshal(buf.Bytes(), &res); err != nil {
361
-		t.Fatal(err)
362
-	}
363
-	if res["Test"].TestNum[0] != v.TestNum[0] {
364
-		t.Fatalf("TestNum %d, expected %d", res["Test"].TestNum, v.TestNum)
365
-	}
366
-}
367 1
deleted file mode 100644
... ...
@@ -1,21 +0,0 @@
1
-package engine
2
-
3
-type Hack map[string]interface{}
4
-
5
-func (eng *Engine) HackGetGlobalVar(key string) interface{} {
6
-	if eng.hack == nil {
7
-		return nil
8
-	}
9
-	val, exists := eng.hack[key]
10
-	if !exists {
11
-		return nil
12
-	}
13
-	return val
14
-}
15
-
16
-func (eng *Engine) HackSetGlobalVar(key string, val interface{}) {
17
-	if eng.hack == nil {
18
-		eng.hack = make(Hack)
19
-	}
20
-	eng.hack[key] = val
21
-}
22 1
deleted file mode 100644
... ...
@@ -1,11 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"testing"
5
-)
6
-
7
-var globalTestID string
8
-
9
-func mkJob(t *testing.T, name string, args ...string) *Job {
10
-	return New().Job(name, args...)
11
-}
12 1
deleted file mode 100644
... ...
@@ -1,42 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"net/http"
5
-	"path"
6
-)
7
-
8
-// ServeHTTP executes a job as specified by the http request `r`, and sends the
9
-// result as an http response.
10
-// This method allows an Engine instance to be passed as a standard http.Handler interface.
11
-//
12
-// Note that the protocol used in this method is a convenience wrapper and is not the canonical
13
-// implementation of remote job execution. This is because HTTP/1 does not handle stream multiplexing,
14
-// and so cannot differentiate stdout from stderr. Additionally, headers cannot be added to a response
15
-// once data has been written to the body, which makes it inconvenient to return metadata such
16
-// as the exit status.
17
-//
18
-func (eng *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
19
-	var (
20
-		jobName         = path.Base(r.URL.Path)
21
-		jobArgs, exists = r.URL.Query()["a"]
22
-	)
23
-	if !exists {
24
-		jobArgs = []string{}
25
-	}
26
-	w.Header().Set("Job-Name", jobName)
27
-	for _, arg := range jobArgs {
28
-		w.Header().Add("Job-Args", arg)
29
-	}
30
-	job := eng.Job(jobName, jobArgs...)
31
-	job.Stdout.Add(w)
32
-	job.Stderr.Add(w)
33
-	// FIXME: distinguish job status from engine error in Run()
34
-	// The former should be passed as a special header, the former
35
-	// should cause a 500 status
36
-	w.WriteHeader(http.StatusOK)
37
-	// The exit status cannot be sent reliably with HTTP1, because headers
38
-	// can only be sent before the body.
39
-	// (we could possibly use http footers via chunked encoding, but I couldn't find
40
-	// how to use them in net/http)
41
-	job.Run()
42
-}
43 1
deleted file mode 100644
... ...
@@ -1,222 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"bytes"
5
-	"fmt"
6
-	"io"
7
-	"strings"
8
-	"sync"
9
-	"time"
10
-
11
-	"github.com/Sirupsen/logrus"
12
-)
13
-
14
-// A job is the fundamental unit of work in the docker engine.
15
-// Everything docker can do should eventually be exposed as a job.
16
-// For example: execute a process in a container, create a new container,
17
-// download an archive from the internet, serve the http api, etc.
18
-//
19
-// The job API is designed after unix processes: a job has a name, arguments,
20
-// environment variables, standard streams for input, output and error.
21
-type Job struct {
22
-	Eng     *Engine
23
-	Name    string
24
-	Args    []string
25
-	env     *Env
26
-	Stdout  *Output
27
-	Stderr  *Output
28
-	Stdin   *Input
29
-	handler Handler
30
-	end     time.Time
31
-	closeIO bool
32
-
33
-	// When closed, the job has been cancelled.
34
-	// Note: not all jobs implement cancellation.
35
-	// See Job.Cancel() and Job.WaitCancelled()
36
-	cancelled  chan struct{}
37
-	cancelOnce sync.Once
38
-}
39
-
40
-// Run executes the job and blocks until the job completes.
41
-// If the job fails it returns an error
42
-func (job *Job) Run() (err error) {
43
-	defer func() {
44
-		// Wait for all background tasks to complete
45
-		if job.closeIO {
46
-			if err := job.Stdout.Close(); err != nil {
47
-				logrus.Error(err)
48
-			}
49
-			if err := job.Stderr.Close(); err != nil {
50
-				logrus.Error(err)
51
-			}
52
-			if err := job.Stdin.Close(); err != nil {
53
-				logrus.Error(err)
54
-			}
55
-		}
56
-	}()
57
-
58
-	if job.Eng.IsShutdown() && !job.GetenvBool("overrideShutdown") {
59
-		return fmt.Errorf("engine is shutdown")
60
-	}
61
-	// FIXME: this is a temporary workaround to avoid Engine.Shutdown
62
-	// waiting 5 seconds for server/api.ServeApi to complete (which it never will)
63
-	// everytime the daemon is cleanly restarted.
64
-	// The permanent fix is to implement Job.Stop and Job.OnStop so that
65
-	// ServeApi can cooperate and terminate cleanly.
66
-	if job.Name != "serveapi" {
67
-		job.Eng.l.Lock()
68
-		job.Eng.tasks.Add(1)
69
-		job.Eng.l.Unlock()
70
-		defer job.Eng.tasks.Done()
71
-	}
72
-	// FIXME: make this thread-safe
73
-	// FIXME: implement wait
74
-	if !job.end.IsZero() {
75
-		return fmt.Errorf("%s: job has already completed", job.Name)
76
-	}
77
-	// Log beginning and end of the job
78
-	if job.Eng.Logging {
79
-		logrus.Infof("+job %s", job.CallString())
80
-		defer func() {
81
-			okerr := "OK"
82
-			if err != nil {
83
-				okerr = fmt.Sprintf("ERR: %s", err)
84
-			}
85
-			logrus.Infof("-job %s %s", job.CallString(), okerr)
86
-		}()
87
-	}
88
-
89
-	if job.handler == nil {
90
-		return fmt.Errorf("%s: command not found", job.Name)
91
-	}
92
-
93
-	var errorMessage = bytes.NewBuffer(nil)
94
-	job.Stderr.Add(errorMessage)
95
-
96
-	err = job.handler(job)
97
-	job.end = time.Now()
98
-
99
-	return
100
-}
101
-
102
-func (job *Job) CallString() string {
103
-	return fmt.Sprintf("%s(%s)", job.Name, strings.Join(job.Args, ", "))
104
-}
105
-
106
-func (job *Job) Env() *Env {
107
-	return job.env
108
-}
109
-
110
-func (job *Job) EnvExists(key string) (value bool) {
111
-	return job.env.Exists(key)
112
-}
113
-
114
-func (job *Job) Getenv(key string) (value string) {
115
-	return job.env.Get(key)
116
-}
117
-
118
-func (job *Job) GetenvBool(key string) (value bool) {
119
-	return job.env.GetBool(key)
120
-}
121
-
122
-func (job *Job) SetenvBool(key string, value bool) {
123
-	job.env.SetBool(key, value)
124
-}
125
-
126
-func (job *Job) GetenvTime(key string) (value time.Time, err error) {
127
-	return job.env.GetTime(key)
128
-}
129
-
130
-func (job *Job) SetenvTime(key string, value time.Time) {
131
-	job.env.SetTime(key, value)
132
-}
133
-
134
-func (job *Job) GetenvSubEnv(key string) *Env {
135
-	return job.env.GetSubEnv(key)
136
-}
137
-
138
-func (job *Job) SetenvSubEnv(key string, value *Env) error {
139
-	return job.env.SetSubEnv(key, value)
140
-}
141
-
142
-func (job *Job) GetenvInt64(key string) int64 {
143
-	return job.env.GetInt64(key)
144
-}
145
-
146
-func (job *Job) GetenvInt(key string) int {
147
-	return job.env.GetInt(key)
148
-}
149
-
150
-func (job *Job) SetenvInt64(key string, value int64) {
151
-	job.env.SetInt64(key, value)
152
-}
153
-
154
-func (job *Job) SetenvInt(key string, value int) {
155
-	job.env.SetInt(key, value)
156
-}
157
-
158
-// Returns nil if key not found
159
-func (job *Job) GetenvList(key string) []string {
160
-	return job.env.GetList(key)
161
-}
162
-
163
-func (job *Job) GetenvJson(key string, iface interface{}) error {
164
-	return job.env.GetJson(key, iface)
165
-}
166
-
167
-func (job *Job) SetenvJson(key string, value interface{}) error {
168
-	return job.env.SetJson(key, value)
169
-}
170
-
171
-func (job *Job) SetenvList(key string, value []string) error {
172
-	return job.env.SetJson(key, value)
173
-}
174
-
175
-func (job *Job) Setenv(key, value string) {
176
-	job.env.Set(key, value)
177
-}
178
-
179
-// DecodeEnv decodes `src` as a json dictionary, and adds
180
-// each decoded key-value pair to the environment.
181
-//
182
-// If `src` cannot be decoded as a json dictionary, an error
183
-// is returned.
184
-func (job *Job) DecodeEnv(src io.Reader) error {
185
-	return job.env.Decode(src)
186
-}
187
-
188
-func (job *Job) EncodeEnv(dst io.Writer) error {
189
-	return job.env.Encode(dst)
190
-}
191
-
192
-func (job *Job) ImportEnv(src interface{}) (err error) {
193
-	return job.env.Import(src)
194
-}
195
-
196
-func (job *Job) Environ() map[string]string {
197
-	return job.env.Map()
198
-}
199
-
200
-func (job *Job) Printf(format string, args ...interface{}) (n int, err error) {
201
-	return fmt.Fprintf(job.Stdout, format, args...)
202
-}
203
-
204
-func (job *Job) Errorf(format string, args ...interface{}) (n int, err error) {
205
-	return fmt.Fprintf(job.Stderr, format, args...)
206
-}
207
-
208
-func (job *Job) SetCloseIO(val bool) {
209
-	job.closeIO = val
210
-}
211
-
212
-// When called, causes the Job.WaitCancelled channel to unblock.
213
-func (job *Job) Cancel() {
214
-	job.cancelOnce.Do(func() {
215
-		close(job.cancelled)
216
-	})
217
-}
218
-
219
-// Returns a channel which is closed ("never blocks") when the job is cancelled.
220
-func (job *Job) WaitCancelled() <-chan struct{} {
221
-	return job.cancelled
222
-}
223 1
deleted file mode 100644
... ...
@@ -1,47 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"bytes"
5
-	"errors"
6
-	"fmt"
7
-	"testing"
8
-)
9
-
10
-func TestJobOK(t *testing.T) {
11
-	eng := New()
12
-	eng.Register("return_ok", func(job *Job) error { return nil })
13
-	err := eng.Job("return_ok").Run()
14
-	if err != nil {
15
-		t.Fatalf("Expected: err=%v\nReceived: err=%v", nil, err)
16
-	}
17
-}
18
-
19
-func TestJobErr(t *testing.T) {
20
-	eng := New()
21
-	eng.Register("return_err", func(job *Job) error { return errors.New("return_err") })
22
-	err := eng.Job("return_err").Run()
23
-	if err == nil {
24
-		t.Fatalf("When a job returns error, Run() should return an error")
25
-	}
26
-}
27
-
28
-func TestJobStdoutString(t *testing.T) {
29
-	eng := New()
30
-	// FIXME: test multiple combinations of output and status
31
-	eng.Register("say_something_in_stdout", func(job *Job) error {
32
-		job.Printf("Hello world\n")
33
-		return nil
34
-	})
35
-
36
-	job := eng.Job("say_something_in_stdout")
37
-	var outputBuffer = bytes.NewBuffer(nil)
38
-	job.Stdout.Add(outputBuffer)
39
-	if err := job.Run(); err != nil {
40
-		t.Fatal(err)
41
-	}
42
-	fmt.Println(outputBuffer)
43
-	var output = Tail(outputBuffer, 1)
44
-	if expectedOutput := "Hello world"; output != expectedOutput {
45
-		t.Fatalf("Stdout last line:\nExpected: %v\nReceived: %v", expectedOutput, output)
46
-	}
47
-}
48 1
deleted file mode 100644
... ...
@@ -1,78 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"testing"
5
-	"time"
6
-)
7
-
8
-func TestShutdownEmpty(t *testing.T) {
9
-	eng := New()
10
-	if eng.IsShutdown() {
11
-		t.Fatalf("IsShutdown should be false")
12
-	}
13
-	eng.Shutdown()
14
-	if !eng.IsShutdown() {
15
-		t.Fatalf("IsShutdown should be true")
16
-	}
17
-}
18
-
19
-func TestShutdownAfterRun(t *testing.T) {
20
-	eng := New()
21
-	eng.Register("foo", func(job *Job) error {
22
-		return nil
23
-	})
24
-	if err := eng.Job("foo").Run(); err != nil {
25
-		t.Fatal(err)
26
-	}
27
-	eng.Shutdown()
28
-	if err := eng.Job("foo").Run(); err == nil {
29
-		t.Fatalf("%#v", *eng)
30
-	}
31
-}
32
-
33
-// An approximate and racy, but better-than-nothing test that
34
-//
35
-func TestShutdownDuringRun(t *testing.T) {
36
-	var (
37
-		jobDelay     time.Duration = 500 * time.Millisecond
38
-		jobDelayLow  time.Duration = 100 * time.Millisecond
39
-		jobDelayHigh time.Duration = 700 * time.Millisecond
40
-	)
41
-	eng := New()
42
-	var completed bool
43
-	eng.Register("foo", func(job *Job) error {
44
-		time.Sleep(jobDelay)
45
-		completed = true
46
-		return nil
47
-	})
48
-	go eng.Job("foo").Run()
49
-	time.Sleep(50 * time.Millisecond)
50
-	done := make(chan struct{})
51
-	var startShutdown time.Time
52
-	go func() {
53
-		startShutdown = time.Now()
54
-		eng.Shutdown()
55
-		close(done)
56
-	}()
57
-	time.Sleep(50 * time.Millisecond)
58
-	if err := eng.Job("foo").Run(); err == nil {
59
-		t.Fatalf("run on shutdown should fail: %#v", *eng)
60
-	}
61
-	<-done
62
-	// Verify that Shutdown() blocks for roughly 500ms, instead
63
-	// of returning almost instantly.
64
-	//
65
-	// We use >100ms to leave ample margin for race conditions between
66
-	// goroutines. It's possible (but unlikely in reasonable testing
67
-	// conditions), that this test will cause a false positive or false
68
-	// negative. But it's probably better than not having any test
69
-	// for the 99.999% of time where testing conditions are reasonable.
70
-	if d := time.Since(startShutdown); d.Nanoseconds() < jobDelayLow.Nanoseconds() {
71
-		t.Fatalf("shutdown did not block long enough: %v", d)
72
-	} else if d.Nanoseconds() > jobDelayHigh.Nanoseconds() {
73
-		t.Fatalf("shutdown blocked too long: %v", d)
74
-	}
75
-	if !completed {
76
-		t.Fatalf("job did not complete")
77
-	}
78
-}
79 1
deleted file mode 100644
... ...
@@ -1,188 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"bytes"
5
-	"fmt"
6
-	"io"
7
-	"strings"
8
-	"sync"
9
-	"unicode"
10
-)
11
-
12
-type Output struct {
13
-	sync.Mutex
14
-	dests []io.Writer
15
-	tasks sync.WaitGroup
16
-	used  bool
17
-}
18
-
19
-// Tail returns the n last lines of a buffer
20
-// stripped out of trailing white spaces, if any.
21
-//
22
-// if n <= 0, returns an empty string
23
-func Tail(buffer *bytes.Buffer, n int) string {
24
-	if n <= 0 {
25
-		return ""
26
-	}
27
-	s := strings.TrimRightFunc(buffer.String(), unicode.IsSpace)
28
-	i := len(s) - 1
29
-	for ; i >= 0 && n > 0; i-- {
30
-		if s[i] == '\n' {
31
-			n--
32
-			if n == 0 {
33
-				break
34
-			}
35
-		}
36
-	}
37
-	// when i == -1, return the whole string which is s[0:]
38
-	return s[i+1:]
39
-}
40
-
41
-// NewOutput returns a new Output object with no destinations attached.
42
-// Writing to an empty Output will cause the written data to be discarded.
43
-func NewOutput() *Output {
44
-	return &Output{}
45
-}
46
-
47
-// Return true if something was written on this output
48
-func (o *Output) Used() bool {
49
-	o.Lock()
50
-	defer o.Unlock()
51
-	return o.used
52
-}
53
-
54
-// Add attaches a new destination to the Output. Any data subsequently written
55
-// to the output will be written to the new destination in addition to all the others.
56
-// This method is thread-safe.
57
-func (o *Output) Add(dst io.Writer) {
58
-	o.Lock()
59
-	defer o.Unlock()
60
-	o.dests = append(o.dests, dst)
61
-}
62
-
63
-// Set closes and remove existing destination and then attaches a new destination to
64
-// the Output. Any data subsequently written to the output will be written to the new
65
-// destination in addition to all the others. This method is thread-safe.
66
-func (o *Output) Set(dst io.Writer) {
67
-	o.Close()
68
-	o.Lock()
69
-	defer o.Unlock()
70
-	o.dests = []io.Writer{dst}
71
-}
72
-
73
-// AddPipe creates an in-memory pipe with io.Pipe(), adds its writing end as a destination,
74
-// and returns its reading end for consumption by the caller.
75
-// This is a rough equivalent similar to Cmd.StdoutPipe() in the standard os/exec package.
76
-// This method is thread-safe.
77
-func (o *Output) AddPipe() (io.Reader, error) {
78
-	r, w := io.Pipe()
79
-	o.Add(w)
80
-	return r, nil
81
-}
82
-
83
-// Write writes the same data to all registered destinations.
84
-// This method is thread-safe.
85
-func (o *Output) Write(p []byte) (n int, err error) {
86
-	o.Lock()
87
-	defer o.Unlock()
88
-	o.used = true
89
-	var firstErr error
90
-	for _, dst := range o.dests {
91
-		_, err := dst.Write(p)
92
-		if err != nil && firstErr == nil {
93
-			firstErr = err
94
-		}
95
-	}
96
-	return len(p), firstErr
97
-}
98
-
99
-// Close unregisters all destinations and waits for all background
100
-// AddTail and AddString tasks to complete.
101
-// The Close method of each destination is called if it exists.
102
-func (o *Output) Close() error {
103
-	o.Lock()
104
-	defer o.Unlock()
105
-	var firstErr error
106
-	for _, dst := range o.dests {
107
-		if closer, ok := dst.(io.Closer); ok {
108
-			err := closer.Close()
109
-			if err != nil && firstErr == nil {
110
-				firstErr = err
111
-			}
112
-		}
113
-	}
114
-	o.tasks.Wait()
115
-	o.dests = nil
116
-	return firstErr
117
-}
118
-
119
-type Input struct {
120
-	src io.Reader
121
-	sync.Mutex
122
-}
123
-
124
-// NewInput returns a new Input object with no source attached.
125
-// Reading to an empty Input will return io.EOF.
126
-func NewInput() *Input {
127
-	return &Input{}
128
-}
129
-
130
-// Read reads from the input in a thread-safe way.
131
-func (i *Input) Read(p []byte) (n int, err error) {
132
-	i.Mutex.Lock()
133
-	defer i.Mutex.Unlock()
134
-	if i.src == nil {
135
-		return 0, io.EOF
136
-	}
137
-	return i.src.Read(p)
138
-}
139
-
140
-// Closes the src
141
-// Not thread safe on purpose
142
-func (i *Input) Close() error {
143
-	if i.src != nil {
144
-		if closer, ok := i.src.(io.Closer); ok {
145
-			return closer.Close()
146
-		}
147
-	}
148
-	return nil
149
-}
150
-
151
-// Add attaches a new source to the input.
152
-// Add can only be called once per input. Subsequent calls will
153
-// return an error.
154
-func (i *Input) Add(src io.Reader) error {
155
-	i.Mutex.Lock()
156
-	defer i.Mutex.Unlock()
157
-	if i.src != nil {
158
-		return fmt.Errorf("Maximum number of sources reached: 1")
159
-	}
160
-	i.src = src
161
-	return nil
162
-}
163
-
164
-// AddEnv starts a new goroutine which will decode all subsequent data
165
-// as a stream of json-encoded objects, and point `dst` to the last
166
-// decoded object.
167
-// The result `env` can be queried using the type-neutral Env interface.
168
-// It is not safe to query `env` until the Output is closed.
169
-func (o *Output) AddEnv() (dst *Env, err error) {
170
-	src, err := o.AddPipe()
171
-	if err != nil {
172
-		return nil, err
173
-	}
174
-	dst = &Env{}
175
-	o.tasks.Add(1)
176
-	go func() {
177
-		defer o.tasks.Done()
178
-		decoder := NewDecoder(src)
179
-		for {
180
-			env, err := decoder.Decode()
181
-			if err != nil {
182
-				return
183
-			}
184
-			*dst = *env
185
-		}
186
-	}()
187
-	return dst, nil
188
-}
189 1
deleted file mode 100644
... ...
@@ -1,215 +0,0 @@
1
-package engine
2
-
3
-import (
4
-	"bufio"
5
-	"bytes"
6
-	"fmt"
7
-	"io"
8
-	"io/ioutil"
9
-	"strings"
10
-	"testing"
11
-)
12
-
13
-type sentinelWriteCloser struct {
14
-	calledWrite bool
15
-	calledClose bool
16
-}
17
-
18
-func (w *sentinelWriteCloser) Write(p []byte) (int, error) {
19
-	w.calledWrite = true
20
-	return len(p), nil
21
-}
22
-
23
-func (w *sentinelWriteCloser) Close() error {
24
-	w.calledClose = true
25
-	return nil
26
-}
27
-
28
-func TestOutputAddEnv(t *testing.T) {
29
-	input := "{\"foo\": \"bar\", \"answer_to_life_the_universe_and_everything\": 42}"
30
-	o := NewOutput()
31
-	result, err := o.AddEnv()
32
-	if err != nil {
33
-		t.Fatal(err)
34
-	}
35
-	o.Write([]byte(input))
36
-	o.Close()
37
-	if v := result.Get("foo"); v != "bar" {
38
-		t.Errorf("Expected %v, got %v", "bar", v)
39
-	}
40
-	if v := result.GetInt("answer_to_life_the_universe_and_everything"); v != 42 {
41
-		t.Errorf("Expected %v, got %v", 42, v)
42
-	}
43
-	if v := result.Get("this-value-doesnt-exist"); v != "" {
44
-		t.Errorf("Expected %v, got %v", "", v)
45
-	}
46
-}
47
-
48
-func TestOutputAddClose(t *testing.T) {
49
-	o := NewOutput()
50
-	var s sentinelWriteCloser
51
-	o.Add(&s)
52
-	if err := o.Close(); err != nil {
53
-		t.Fatal(err)
54
-	}
55
-	// Write data after the output is closed.
56
-	// Write should succeed, but no destination should receive it.
57
-	if _, err := o.Write([]byte("foo bar")); err != nil {
58
-		t.Fatal(err)
59
-	}
60
-	if !s.calledClose {
61
-		t.Fatal("Output.Close() didn't close the destination")
62
-	}
63
-}
64
-
65
-func TestOutputAddPipe(t *testing.T) {
66
-	var testInputs = []string{
67
-		"hello, world!",
68
-		"One\nTwo\nThree",
69
-		"",
70
-		"A line\nThen another nl-terminated line\n",
71
-		"A line followed by an empty line\n\n",
72
-	}
73
-	for _, input := range testInputs {
74
-		expectedOutput := input
75
-		o := NewOutput()
76
-		r, err := o.AddPipe()
77
-		if err != nil {
78
-			t.Fatal(err)
79
-		}
80
-		go func(o *Output) {
81
-			if n, err := o.Write([]byte(input)); err != nil {
82
-				t.Error(err)
83
-			} else if n != len(input) {
84
-				t.Errorf("Expected %d, got %d", len(input), n)
85
-			}
86
-			if err := o.Close(); err != nil {
87
-				t.Error(err)
88
-			}
89
-		}(o)
90
-		output, err := ioutil.ReadAll(r)
91
-		if err != nil {
92
-			t.Fatal(err)
93
-		}
94
-		if string(output) != expectedOutput {
95
-			t.Errorf("Last line is not stored as return string.\nExpected: '%s'\nGot:       '%s'", expectedOutput, output)
96
-		}
97
-	}
98
-}
99
-
100
-func TestTail(t *testing.T) {
101
-	var tests = make(map[string][]string)
102
-	tests["hello, world!"] = []string{
103
-		"",
104
-		"hello, world!",
105
-		"hello, world!",
106
-		"hello, world!",
107
-	}
108
-	tests["One\nTwo\nThree"] = []string{
109
-		"",
110
-		"Three",
111
-		"Two\nThree",
112
-		"One\nTwo\nThree",
113
-	}
114
-	tests["One\nTwo\n\n\n"] = []string{
115
-		"",
116
-		"Two",
117
-		"One\nTwo",
118
-	}
119
-	for input, outputs := range tests {
120
-		for n, expectedOutput := range outputs {
121
-			output := Tail(bytes.NewBufferString(input), n)
122
-			if output != expectedOutput {
123
-				t.Errorf("Tail n=%d returned wrong result.\nExpected: '%s'\nGot     : '%s'", n, expectedOutput, output)
124
-			}
125
-		}
126
-	}
127
-}
128
-
129
-func lastLine(txt string) string {
130
-	scanner := bufio.NewScanner(strings.NewReader(txt))
131
-	var lastLine string
132
-	for scanner.Scan() {
133
-		lastLine = scanner.Text()
134
-	}
135
-	return lastLine
136
-}
137
-
138
-func TestOutputAdd(t *testing.T) {
139
-	o := NewOutput()
140
-	b := &bytes.Buffer{}
141
-	o.Add(b)
142
-	input := "hello, world!"
143
-	if n, err := o.Write([]byte(input)); err != nil {
144
-		t.Fatal(err)
145
-	} else if n != len(input) {
146
-		t.Fatalf("Expected %d, got %d", len(input), n)
147
-	}
148
-	if output := b.String(); output != input {
149
-		t.Fatalf("Received wrong data from Add.\nExpected: '%s'\nGot:     '%s'", input, output)
150
-	}
151
-}
152
-
153
-func TestOutputWriteError(t *testing.T) {
154
-	o := NewOutput()
155
-	buf := &bytes.Buffer{}
156
-	o.Add(buf)
157
-	r, w := io.Pipe()
158
-	input := "Hello there"
159
-	expectedErr := fmt.Errorf("This is an error")
160
-	r.CloseWithError(expectedErr)
161
-	o.Add(w)
162
-	n, err := o.Write([]byte(input))
163
-	if err != expectedErr {
164
-		t.Fatalf("Output.Write() should return the first error encountered, if any")
165
-	}
166
-	if buf.String() != input {
167
-		t.Fatalf("Output.Write() should attempt write on all destinations, even after encountering an error")
168
-	}
169
-	if n != len(input) {
170
-		t.Fatalf("Output.Write() should return the size of the input if it successfully writes to at least one destination")
171
-	}
172
-}
173
-
174
-func TestInputAddEmpty(t *testing.T) {
175
-	i := NewInput()
176
-	var b bytes.Buffer
177
-	if err := i.Add(&b); err != nil {
178
-		t.Fatal(err)
179
-	}
180
-	data, err := ioutil.ReadAll(i)
181
-	if err != nil {
182
-		t.Fatal(err)
183
-	}
184
-	if len(data) > 0 {
185
-		t.Fatalf("Read from empty input should yield no data")
186
-	}
187
-}
188
-
189
-func TestInputAddTwo(t *testing.T) {
190
-	i := NewInput()
191
-	var b1 bytes.Buffer
192
-	// First add should succeed
193
-	if err := i.Add(&b1); err != nil {
194
-		t.Fatal(err)
195
-	}
196
-	var b2 bytes.Buffer
197
-	// Second add should fail
198
-	if err := i.Add(&b2); err == nil {
199
-		t.Fatalf("Adding a second source should return an error")
200
-	}
201
-}
202
-
203
-func TestInputAddNotEmpty(t *testing.T) {
204
-	i := NewInput()
205
-	b := bytes.NewBufferString("hello world\nabc")
206
-	expectedResult := b.String()
207
-	i.Add(b)
208
-	result, err := ioutil.ReadAll(i)
209
-	if err != nil {
210
-		t.Fatal(err)
211
-	}
212
-	if string(result) != expectedResult {
213
-		t.Fatalf("Expected: %v\nReceived: %v", expectedResult, result)
214
-	}
215
-}
... ...
@@ -24,15 +24,15 @@ func checkPidFileAlreadyExists(path string) error {
24 24
 	return nil
25 25
 }
26 26
 
27
-func New(path string) (file *PidFile, err error) {
27
+func New(path string) (*PidFile, error) {
28 28
 	if err := checkPidFileAlreadyExists(path); err != nil {
29 29
 		return nil, err
30 30
 	}
31
+	if err := ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
32
+		return nil, err
33
+	}
31 34
 
32
-	file = &PidFile{path: path}
33
-	err = ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644)
34
-
35
-	return file, err
35
+	return &PidFile{path: path}, nil
36 36
 }
37 37
 
38 38
 func (file PidFile) Remove() error {