Skip to content

Commit 895f883

Browse files
committed
Add -interval option
Allows a config file and notify command to be run on a scheduled interval. This can be useful for service registration use cases.
1 parent 64266ae commit 895f883

File tree

2 files changed

+75
-23
lines changed

2 files changed

+75
-23
lines changed

docker-gen.go

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ import (
1313
"os"
1414
"os/exec"
1515
"os/signal"
16-
1716
"strings"
17+
"sync"
1818
"syscall"
19+
"time"
1920
)
2021

2122
var (
@@ -24,6 +25,8 @@ var (
2425
onlyExposed bool
2526
configFile string
2627
configs ConfigFile
28+
interval int
29+
wg sync.WaitGroup
2730
)
2831

2932
type Event struct {
@@ -49,6 +52,7 @@ type Config struct {
4952
Watch bool
5053
NotifyCmd string
5154
OnlyExposed bool
55+
Interval int
5256
}
5357

5458
type ConfigFile struct {
@@ -73,7 +77,7 @@ func (r *RuntimeContainer) Equals(o RuntimeContainer) bool {
7377
}
7478

7579
func usage() {
76-
println("Usage: docker-gen [-config file] [-watch=false] [-notify=\"restart xyz\"] <template> [<dest>]")
80+
println("Usage: docker-gen [-config file] [-watch=false] [-notify=\"restart xyz\"] [-interval=0] <template> [<dest>]")
7781
}
7882

7983
func newConn() (*httputil.ClientConn, error) {
@@ -141,13 +145,12 @@ func getEvents() chan *Event {
141145
return eventChan
142146
}
143147

144-
func generateFromContainers(client *docker.Client) {
148+
func getContainers(client *docker.Client) ([]*RuntimeContainer, error) {
145149
apiContainers, err := client.ListContainers(docker.ListContainersOptions{
146150
All: false,
147151
})
148152
if err != nil {
149-
fmt.Printf("error listing containers: %s\n", err)
150-
return
153+
return nil, err
151154
}
152155

153156
containers := []*RuntimeContainer{}
@@ -179,15 +182,21 @@ func generateFromContainers(client *docker.Client) {
179182

180183
containers = append(containers, runtimeContainer)
181184
}
185+
return containers, nil
182186

187+
}
188+
func generateFromContainers(client *docker.Client) {
189+
containers, err := getContainers(client)
190+
if err != nil {
191+
fmt.Printf("error listing containers: %s\n", err)
192+
return
193+
}
183194
for _, config := range configs.Config {
184195
changed := generateFile(config, containers)
185196
if changed {
186197
runNotifyCmd(config)
187198
}
188-
189199
}
190-
191200
}
192201

193202
func runNotifyCmd(config Config) {
@@ -212,11 +221,62 @@ func loadConfig(file string) error {
212221
return nil
213222
}
214223

224+
func generateAtInterval(client *docker.Client, configs ConfigFile) {
225+
for _, config := range configs.Config {
226+
227+
if config.Interval == 0 {
228+
continue
229+
}
230+
231+
wg.Add(1)
232+
ticker := time.NewTicker(time.Duration(config.Interval) * time.Second)
233+
quit := make(chan struct{})
234+
go func() {
235+
for {
236+
select {
237+
case <-ticker.C:
238+
containers, err := getContainers(client)
239+
if err != nil {
240+
fmt.Printf("error listing containers: %s\n", err)
241+
continue
242+
}
243+
// ignore changed return value. always run notify command
244+
generateFile(config, containers)
245+
runNotifyCmd(config)
246+
case <-quit:
247+
ticker.Stop()
248+
return
249+
}
250+
}
251+
wg.Done()
252+
}()
253+
}
254+
}
255+
256+
func generateFromEvents(client *docker.Client, configs ConfigFile) {
257+
configs = configs.filterWatches()
258+
if len(configs.Config) == 0 {
259+
return
260+
}
261+
262+
wg.Add(1)
263+
eventChan := getEvents()
264+
for {
265+
event := <-eventChan
266+
if event.Status == "start" || event.Status == "stop" || event.Status == "die" {
267+
generateFromContainers(client)
268+
}
269+
}
270+
wg.Done()
271+
272+
}
273+
215274
func main() {
216275
flag.BoolVar(&watch, "watch", false, "watch for container changes")
217276
flag.BoolVar(&onlyExposed, "only-exposed", false, "only include containers with exposed ports")
218277
flag.StringVar(&notifyCmd, "notify", "", "run command after template is regenerated")
219278
flag.StringVar(&configFile, "config", "", "config file with template directives")
279+
flag.IntVar(&interval, "interval", 0, "notify command interval (s)")
220280
flag.Parse()
221281

222282
if flag.NArg() < 1 && configFile == "" {
@@ -237,6 +297,7 @@ func main() {
237297
Watch: watch,
238298
NotifyCmd: notifyCmd,
239299
OnlyExposed: onlyExposed,
300+
Interval: interval,
240301
}
241302
configs = ConfigFile{
242303
Config: []Config{config}}
@@ -250,19 +311,7 @@ func main() {
250311
}
251312

252313
generateFromContainers(client)
253-
254-
configs = configs.filterWatches()
255-
256-
if len(configs.Config) == 0 {
257-
return
258-
}
259-
260-
eventChan := getEvents()
261-
for {
262-
event := <-eventChan
263-
if event.Status == "start" || event.Status == "stop" || event.Status == "die" {
264-
generateFromContainers(client)
265-
}
266-
}
267-
314+
generateAtInterval(client, configs)
315+
generateFromEvents(client, configs)
316+
wg.Wait()
268317
}

template.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ func generateFile(config Config, containers []*RuntimeContainer) bool {
5555
dest := os.Stdout
5656
if config.Dest != "" {
5757
dest, err = ioutil.TempFile("", "docker-gen")
58-
defer dest.Close()
58+
defer func() {
59+
dest.Close()
60+
os.Remove(dest.Name())
61+
}()
5962
if err != nil {
6063
fmt.Printf("unable to create temp file: %s\n", err)
6164
os.Exit(1)

0 commit comments

Comments
 (0)