Browse code

Setup daemon pidfile/cleanup in Server.Daemon() instead of main()

Solomon Hykes authored on 2013/10/25 15:30:34
Showing 3 changed files
... ...
@@ -7,13 +7,9 @@ import (
7 7
 	"github.com/dotcloud/docker/sysinit"
8 8
 	"github.com/dotcloud/docker/utils"
9 9
 	"github.com/dotcloud/docker/engine"
10
-	"io/ioutil"
11 10
 	"log"
12 11
 	"os"
13
-	"os/signal"
14
-	"strconv"
15 12
 	"strings"
16
-	"syscall"
17 13
 )
18 14
 
19 15
 var (
... ...
@@ -89,7 +85,7 @@ func main() {
89 89
 		job.SetenvList("ProtoAddresses", flHosts)
90 90
 		job.Setenv("DefaultIp", *flDefaultIp)
91 91
 		job.SetenvBool("InterContainerCommunication", *flInterContainerComm)
92
-		if err := daemon(job, *pidfile); err != nil {
92
+		if err := job.Run(); err != nil {
93 93
 			log.Fatal(err)
94 94
 		}
95 95
 	} else {
... ...
@@ -109,50 +105,3 @@ func main() {
109 109
 func showVersion() {
110 110
 	fmt.Printf("Docker version %s, build %s\n", VERSION, GITCOMMIT)
111 111
 }
112
-
113
-func createPidFile(pidfile string) error {
114
-	if pidString, err := ioutil.ReadFile(pidfile); err == nil {
115
-		pid, err := strconv.Atoi(string(pidString))
116
-		if err == nil {
117
-			if _, err := os.Stat(fmt.Sprintf("/proc/%d/", pid)); err == nil {
118
-				return fmt.Errorf("pid file found, ensure docker is not running or delete %s", pidfile)
119
-			}
120
-		}
121
-	}
122
-
123
-	file, err := os.Create(pidfile)
124
-	if err != nil {
125
-		return err
126
-	}
127
-
128
-	defer file.Close()
129
-
130
-	_, err = fmt.Fprintf(file, "%d", os.Getpid())
131
-	return err
132
-}
133
-
134
-func removePidFile(pidfile string) {
135
-	if err := os.Remove(pidfile); err != nil {
136
-		log.Printf("Error removing %s: %s", pidfile, err)
137
-	}
138
-}
139
-
140
-// daemon runs `job` as a daemon. 
141
-// A pidfile is created for the duration of the job,
142
-// and all signals are intercepted.
143
-func daemon(job *engine.Job, pidfile string) error {
144
-	if err := createPidFile(pidfile); err != nil {
145
-		log.Fatal(err)
146
-	}
147
-	defer removePidFile(pidfile)
148
-
149
-	c := make(chan os.Signal, 1)
150
-	signal.Notify(c, os.Interrupt, os.Kill, os.Signal(syscall.SIGTERM))
151
-	go func() {
152
-		sig := <-c
153
-		log.Printf("Received signal '%v', exiting\n", sig)
154
-		removePidFile(pidfile)
155
-		os.Exit(0)
156
-	}()
157
-	return job.Run()
158
-}
... ...
@@ -24,6 +24,7 @@ import (
24 24
 	"sync"
25 25
 	"time"
26 26
 	"syscall"
27
+	"os/signal"
27 28
 )
28 29
 
29 30
 func (srv *Server) Close() error {
... ...
@@ -40,8 +41,31 @@ func JobServeApi(job *engine.Job) string {
40 40
 		return err.Error()
41 41
 	}
42 42
 	defer srv.Close()
43
-	// Parse addresses to serve on
44
-	protoAddrs := job.Args
43
+	if err := srv.Daemon(); err != nil {
44
+		return err.Error()
45
+	}
46
+	return "0"
47
+}
48
+
49
+// Daemon runs the remote api server `srv` as a daemon,
50
+// Only one api server can run at the same time - this is enforced by a pidfile.
51
+// The signals SIGINT, SIGKILL and SIGTERM are intercepted for cleanup.
52
+func (srv *Server) Daemon() error {
53
+	if err := utils.CreatePidFile(srv.runtime.config.Pidfile); err != nil {
54
+		log.Fatal(err)
55
+	}
56
+	defer utils.RemovePidFile(srv.runtime.config.Pidfile)
57
+
58
+	c := make(chan os.Signal, 1)
59
+	signal.Notify(c, os.Interrupt, os.Kill, os.Signal(syscall.SIGTERM))
60
+	go func() {
61
+		sig := <-c
62
+		log.Printf("Received signal '%v', exiting\n", sig)
63
+		utils.RemovePidFile(srv.runtime.config.Pidfile)
64
+		os.Exit(0)
65
+	}()
66
+
67
+	protoAddrs := srv.runtime.config.ProtoAddresses
45 68
 	chErrors := make(chan error, len(protoAddrs))
46 69
 	for _, protoAddr := range protoAddrs {
47 70
 		protoAddrParts := strings.SplitN(protoAddr, "://", 2)
... ...
@@ -52,7 +76,7 @@ func JobServeApi(job *engine.Job) string {
52 52
 				log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
53 53
 			}
54 54
 		} else {
55
-			return "Invalid protocol format."
55
+			return fmt.Errorf("Invalid protocol format.")
56 56
 		}
57 57
 		go func() {
58 58
 			chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], srv, true)
... ...
@@ -61,12 +85,13 @@ func JobServeApi(job *engine.Job) string {
61 61
 	for i := 0; i < len(protoAddrs); i += 1 {
62 62
 		err := <-chErrors
63 63
 		if err != nil {
64
-			return err.Error()
64
+			return err
65 65
 		}
66 66
 	}
67
-	return "0"
67
+	return nil
68 68
 }
69 69
 
70
+
70 71
 func (srv *Server) DockerVersion() APIVersion {
71 72
 	return APIVersion{
72 73
 		Version:   VERSION,
73 74
new file mode 100644
... ...
@@ -0,0 +1,36 @@
0
+package utils
1
+
2
+import (
3
+	"os"
4
+	"fmt"
5
+	"io/ioutil"
6
+	"log"
7
+	"strconv"
8
+)
9
+
10
+func CreatePidFile(pidfile string) error {
11
+	if pidString, err := ioutil.ReadFile(pidfile); err == nil {
12
+		pid, err := strconv.Atoi(string(pidString))
13
+		if err == nil {
14
+			if _, err := os.Stat(fmt.Sprintf("/proc/%d/", pid)); err == nil {
15
+				return fmt.Errorf("pid file found, ensure docker is not running or delete %s", pidfile)
16
+			}
17
+		}
18
+	}
19
+
20
+	file, err := os.Create(pidfile)
21
+	if err != nil {
22
+		return err
23
+	}
24
+
25
+	defer file.Close()
26
+
27
+	_, err = fmt.Fprintf(file, "%d", os.Getpid())
28
+	return err
29
+}
30
+
31
+func RemovePidFile(pidfile string) {
32
+	if err := os.Remove(pidfile); err != nil {
33
+		log.Printf("Error removing %s: %s", pidfile, err)
34
+	}
35
+}