Skip to content

Commit 94ffc1c

Browse files
committed
Add notify command option
Runs a command after the template is generated. Useful for restarting nginx, haproxy, etc.. Use nginx as an example to add this feature and ended up also needing to simplify how IP:Port info is accessed.
1 parent 7a6cb6f commit 94ffc1c

File tree

3 files changed

+101
-9
lines changed

3 files changed

+101
-9
lines changed

README.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
docker-gen
22
=====
33

4-
Config file generator using running docker container meta-data.
4+
Config file generator using docker container meta-data.
55

6-
This is mostly a proof of concept to generate config files for:
6+
This is can be used to generate config files for:
77

88
* fluentd, logstash or other centralized logging tools that tail the containers JSON log file.
99
* logrotate files to rotate container JSON log files
10+
* nginx, haproxy, etc.. reverse proxy configs to route requests to the host to containers
11+
1012

1113
[Docker Log Management With Fluentd](http://jasonwilder.com/blog/2014/03/17/docker-log-management-using-fluentd/)
1214

@@ -16,9 +18,18 @@ To Run:
1618

1719
`go get github.com/jwilder/docker-gen`
1820

19-
`docker-gen template.file`
21+
`docker-gen`
22+
`Usage: docker-gen [-watch=false] [-notify="restart xyz"] <template> [<dest>]`
23+
24+
Options:
25+
* -watch - runs continuously and monitors docker container events. When containers are started
26+
or stopped, the template is regenerated.
27+
* -notify - runs a command after the template is generated. Useful for restarting nginx, reloading
28+
haproxy, etc..
29+
30+
If no `<dest>` file is specified, the output is send to stdout. Mainly useful for debugging.
2031

2132
TODO:
2233

23-
* Add restart command hooks for when files are regenerated.
24-
* Tail docker event stream to detect when containers are started and stopped automatically
34+
* Add a way to filter out containers in templates
35+

docker-gen.go

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,41 @@ import (
1010
"net/http"
1111
"net/http/httputil"
1212
"os"
13+
"os/exec"
1314
"os/signal"
1415
"path/filepath"
16+
"strings"
1517
"syscall"
1618
"text/template"
1719
)
1820

19-
var watch bool
21+
var (
22+
watch bool
23+
notifyCmd string
24+
)
2025

2126
type Event struct {
2227
ContainerId string `json:"id"`
2328
Status string `json:"status"`
2429
Image string `json:"from"`
2530
}
2631

32+
type Address struct {
33+
IP string
34+
Port string
35+
}
36+
type RuntimeContainer struct {
37+
ID string
38+
Addresses []Address
39+
Image string
40+
}
41+
2742
func usage() {
28-
println("Usage: docker-gen [-watch] <template> [<dest>]")
43+
println("Usage: docker-gen [-watch=false] [-notify=\"restart xyz\"] <template> [<dest>]")
2944
}
3045

31-
func generateFile(templatePath string, containers []docker.APIContainers) {
46+
func generateFile(templatePath string, containers []*RuntimeContainer) {
47+
3248
tmpl, err := template.ParseFiles(templatePath)
3349
if err != nil {
3450
panic(err)
@@ -44,6 +60,9 @@ func generateFile(templatePath string, containers []docker.APIContainers) {
4460
}
4561

4662
err = tmpl.ExecuteTemplate(dest, filepath.Base(templatePath), containers)
63+
if err != nil {
64+
fmt.Printf("template error: %s\n", err)
65+
}
4766
}
4867

4968
func newConn() (*httputil.ClientConn, error) {
@@ -110,20 +129,59 @@ func getEvents() chan *Event {
110129
}
111130

112131
func generateFromContainers(client *docker.Client) {
113-
containers, err := client.ListContainers(docker.ListContainersOptions{
132+
apiContainers, err := client.ListContainers(docker.ListContainersOptions{
114133
All: false,
115134
})
116135
if err != nil {
117136
fmt.Printf("error listing containers: %s", err)
118137
return
119138
}
120139

140+
containers := []*RuntimeContainer{}
141+
for _, apiContainer := range apiContainers {
142+
container, err := client.InspectContainer(apiContainer.ID)
143+
if err != nil {
144+
fmt.Printf("error inspecting container: %s: %s", apiContainer.ID, err)
145+
continue
146+
}
147+
148+
runtimeContainer := &RuntimeContainer{
149+
ID: container.ID,
150+
Image: container.Config.Image,
151+
Addresses: []Address{},
152+
}
153+
for k, _ := range container.NetworkSettings.Ports {
154+
runtimeContainer.Addresses = append(runtimeContainer.Addresses,
155+
Address{
156+
IP: container.NetworkSettings.IPAddress,
157+
Port: k.Port(),
158+
})
159+
}
160+
containers = append(containers, runtimeContainer)
161+
}
162+
121163
generateFile(flag.Arg(0), containers)
122164
}
123165

166+
func runNotifyCmd() {
167+
if notifyCmd == "" {
168+
return
169+
}
170+
171+
args := strings.Split(notifyCmd, " ")
172+
cmd := exec.Command(args[0], args[1:]...)
173+
output, err := cmd.CombinedOutput()
174+
if err != nil {
175+
fmt.Printf("error running notify command: %s\n", err)
176+
}
177+
print(string(output))
178+
179+
}
180+
124181
func main() {
125182

126183
flag.BoolVar(&watch, "watch", false, "watch for container changes")
184+
flag.StringVar(&notifyCmd, "notify", "", "run command after template is regenerated")
127185
flag.Parse()
128186

129187
if flag.NArg() < 1 {
@@ -139,6 +197,7 @@ func main() {
139197
}
140198

141199
generateFromContainers(client)
200+
runNotifyCmd()
142201
if !watch {
143202
return
144203
}
@@ -148,6 +207,7 @@ func main() {
148207
event := <-eventChan
149208
if event.Status == "start" || event.Status == "stop" {
150209
generateFromContainers(client)
210+
runNotifyCmd()
151211
}
152212
}
153213

templates/nginx.tmpl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
upstream docker {
2+
{{range $key, $value := .}}
3+
{}
4+
{{with $address := index $value.Addresses 0 }}
5+
server {{ $address.IP}}:{{ $address.Port}};
6+
{{end}}
7+
{{end}}
8+
}
9+
10+
server {
11+
root /usr/share/nginx/www;
12+
index index.html index.htm;
13+
14+
server_name localhost;
15+
16+
location / {
17+
proxy_pass http://docker;
18+
include /etc/nginx/proxy_params;
19+
}
20+
}
21+

0 commit comments

Comments
 (0)