4
4
"encoding/json"
5
5
"flag"
6
6
"fmt"
7
+ "github.com/BurntSushi/toml"
7
8
"github.com/fsouza/go-dockerclient"
8
9
"io"
9
10
"net"
23
24
watch bool
24
25
notifyCmd string
25
26
onlyExposed bool
27
+ configFile string
28
+ configs ConfigFile
26
29
)
27
30
28
31
type Event struct {
@@ -42,6 +45,31 @@ type RuntimeContainer struct {
42
45
Env map [string ]string
43
46
}
44
47
48
+ type Config struct {
49
+ Template string
50
+ Dest string
51
+ Watch bool
52
+ NotifyCmd string
53
+ OnlyExposed bool
54
+ }
55
+
56
+ type ConfigFile struct {
57
+ Config []Config
58
+ }
59
+
60
+ func (c * ConfigFile ) filterWatches () ConfigFile {
61
+ configWithWatches := []Config {}
62
+
63
+ for _ , config := range c .Config {
64
+ if config .Watch {
65
+ configWithWatches = append (configWithWatches , config )
66
+ }
67
+ }
68
+ return ConfigFile {
69
+ Config : configWithWatches ,
70
+ }
71
+ }
72
+
45
73
func deepGet (item interface {}, path string ) interface {} {
46
74
if path == "" {
47
75
return item
@@ -90,10 +118,11 @@ func contains(a map[string]string, b string) bool {
90
118
}
91
119
92
120
func usage () {
93
- println ("Usage: docker-gen [-watch=false] [-notify=\" restart xyz\" ] <template> [<dest>]" )
121
+ println ("Usage: docker-gen [-config file] [- watch=false] [-notify=\" restart xyz\" ] <template> [<dest>]" )
94
122
}
95
123
96
- func generateFile (templatePath string , containers []* RuntimeContainer ) {
124
+ func generateFile (config Config , containers []* RuntimeContainer ) {
125
+ templatePath := config .Template
97
126
tmpl , err := template .New (filepath .Base (templatePath )).Funcs (template.FuncMap {
98
127
"contains" : contains ,
99
128
"groupBy" : groupBy ,
@@ -102,12 +131,23 @@ func generateFile(templatePath string, containers []*RuntimeContainer) {
102
131
panic (err )
103
132
}
104
133
134
+ filteredContainers := []* RuntimeContainer {}
135
+ if config .OnlyExposed {
136
+ for _ , container := range containers {
137
+ if len (container .Addresses ) > 0 {
138
+ filteredContainers = append (filteredContainers , container )
139
+ }
140
+ }
141
+ } else {
142
+ filteredContainers = containers
143
+ }
144
+
105
145
tmpl = tmpl
106
146
dest := os .Stdout
107
- if flag . NArg () == 2 {
108
- dest , err = os .Create (flag . Arg ( 1 ) )
147
+ if config . Dest != "" {
148
+ dest , err = os .Create (config . Dest )
109
149
if err != nil {
110
- fmt .Println ("unable to create dest file %s: %s\n " , flag . Arg ( 1 ) , err )
150
+ fmt .Println ("unable to create dest file %s: %s\n " , config . Dest , err )
111
151
os .Exit (1 )
112
152
}
113
153
}
@@ -219,46 +259,67 @@ func generateFromContainers(client *docker.Client) {
219
259
runtimeContainer .Env [parts [0 ]] = parts [1 ]
220
260
}
221
261
222
- if ! onlyExposed {
223
- containers = append (containers , runtimeContainer )
224
- continue
225
- }
226
-
227
- if onlyExposed && len (runtimeContainer .Addresses ) > 0 {
228
- containers = append (containers , runtimeContainer )
229
- }
262
+ containers = append (containers , runtimeContainer )
263
+ }
230
264
265
+ for _ , config := range configs .Config {
266
+ generateFile (config , containers )
267
+ runNotifyCmd (config )
231
268
}
232
269
233
- generateFile (flag .Arg (0 ), containers )
234
270
}
235
271
236
- func runNotifyCmd () {
237
- if notifyCmd == "" {
272
+ func runNotifyCmd (config Config ) {
273
+ if config . NotifyCmd == "" {
238
274
return
239
275
}
240
276
241
- args := strings .Split (notifyCmd , " " )
277
+ args := strings .Split (config . NotifyCmd , " " )
242
278
cmd := exec .Command (args [0 ], args [1 :]... )
243
- output , err := cmd .CombinedOutput ()
279
+ _ , err := cmd .CombinedOutput ()
244
280
if err != nil {
245
- fmt .Printf ("error running notify command: %s\n " , err )
281
+ fmt .Printf ("error running notify command: %s, %s \n " , config . NotifyCmd , err )
246
282
}
247
- print ( string ( output ))
283
+ }
248
284
285
+ func loadConfig (file string ) error {
286
+ _ , err := toml .DecodeFile (file , & configs )
287
+ if err != nil {
288
+ return err
289
+ }
290
+ return nil
249
291
}
250
292
251
293
func main () {
252
294
flag .BoolVar (& watch , "watch" , false , "watch for container changes" )
253
295
flag .BoolVar (& onlyExposed , "only-exposed" , false , "only include containers with exposed ports" )
254
296
flag .StringVar (& notifyCmd , "notify" , "" , "run command after template is regenerated" )
297
+ flag .StringVar (& configFile , "config" , "" , "config file with template directives" )
255
298
flag .Parse ()
256
299
257
- if flag .NArg () < 1 {
300
+ if flag .NArg () < 1 && configFile == "" {
258
301
usage ()
259
302
os .Exit (1 )
260
303
}
261
304
305
+ if configFile != "" {
306
+ err := loadConfig (configFile )
307
+ if err != nil {
308
+ fmt .Printf ("error loading config %s: %s\n " , configFile , err )
309
+ os .Exit (1 )
310
+ }
311
+ } else {
312
+ config := Config {
313
+ Template : flag .Arg (0 ),
314
+ Dest : flag .Arg (1 ),
315
+ Watch : watch ,
316
+ NotifyCmd : notifyCmd ,
317
+ OnlyExposed : onlyExposed ,
318
+ }
319
+ configs = ConfigFile {
320
+ Config : []Config {config }}
321
+ }
322
+
262
323
endpoint := "unix:///var/run/docker.sock"
263
324
client , err := docker .NewClient (endpoint )
264
325
@@ -267,8 +328,10 @@ func main() {
267
328
}
268
329
269
330
generateFromContainers (client )
270
- runNotifyCmd ()
271
- if ! watch {
331
+
332
+ configs = configs .filterWatches ()
333
+
334
+ if len (configs .Config ) == 0 {
272
335
return
273
336
}
274
337
@@ -277,7 +340,6 @@ func main() {
277
340
event := <- eventChan
278
341
if event .Status == "start" || event .Status == "stop" || event .Status == "die" {
279
342
generateFromContainers (client )
280
- runNotifyCmd ()
281
343
}
282
344
}
283
345
0 commit comments