11package main
22
33import (
4- "errors"
54 "flag"
65 "fmt"
76 "log"
87 "os"
9- "os/exec"
108 "path/filepath"
11- "strings"
129 "sync"
13- "time"
1410
1511 "github.com/BurntSushi/toml"
1612 docker "github.com/fsouza/go-dockerclient"
4137 wg sync.WaitGroup
4238)
4339
44- type Event struct {
45- ContainerID string `json:"id"`
46- Status string `json:"status"`
47- Image string `json:"from"`
48- }
49-
5040func (strings * stringslice ) String () string {
5141 return "[]"
5242}
@@ -73,90 +63,12 @@ Arguments:
7363 println (`
7464Environment Variables:
7565 DOCKER_HOST - default value for -endpoint
76- DOCKER_CERT_PATH - directory path containing key.pem, cert.pm and ca.pem
66+ DOCKER_CERT_PATH - directory path containing key.pem, cert.pem and ca.pem
7767 DOCKER_TLS_VERIFY - enable client TLS verification
7868` )
7969 println (`For more information, see https://github.com/jwilder/docker-gen` )
8070}
8171
82- func tlsEnabled () bool {
83- for _ , v := range []string {tlsCert , tlsCaCert , tlsKey } {
84- if e , err := pathExists (v ); e && err == nil {
85- return true
86- }
87- }
88- return false
89- }
90-
91- func NewDockerClient (endpoint string ) (* docker.Client , error ) {
92- if strings .HasPrefix (endpoint , "unix:" ) {
93- return docker .NewClient (endpoint )
94- } else if tlsVerify || tlsEnabled () {
95- if tlsVerify {
96- if e , err := pathExists (tlsCaCert ); ! e || err != nil {
97- return nil , errors .New ("TLS verification was requested, but CA cert does not exist" )
98- }
99- }
100-
101- return docker .NewTLSClient (endpoint , tlsCert , tlsKey , tlsCaCert )
102- }
103- return docker .NewClient (endpoint )
104- }
105-
106- func generateFromContainers (client * docker.Client ) {
107- containers , err := dockergen .GetContainers (client )
108- if err != nil {
109- log .Printf ("error listing containers: %s\n " , err )
110- return
111- }
112- for _ , config := range configs .Config {
113- changed := dockergen .GenerateFile (config , containers )
114- if ! changed {
115- log .Printf ("Contents of %s did not change. Skipping notification '%s'" , config .Dest , config .NotifyCmd )
116- continue
117- }
118- runNotifyCmd (config )
119- sendSignalToContainer (client , config )
120- }
121- }
122-
123- func runNotifyCmd (config dockergen.Config ) {
124- if config .NotifyCmd == "" {
125- return
126- }
127-
128- log .Printf ("Running '%s'" , config .NotifyCmd )
129- cmd := exec .Command ("/bin/sh" , "-c" , config .NotifyCmd )
130- out , err := cmd .CombinedOutput ()
131- if err != nil {
132- log .Printf ("Error running notify command: %s, %s\n " , config .NotifyCmd , err )
133- }
134- if config .NotifyOutput {
135- for _ , line := range strings .Split (string (out ), "\n " ) {
136- if line != "" {
137- log .Printf ("[%s]: %s" , config .NotifyCmd , line )
138- }
139- }
140- }
141- }
142-
143- func sendSignalToContainer (client * docker.Client , config dockergen.Config ) {
144- if len (config .NotifyContainers ) < 1 {
145- return
146- }
147-
148- for container , signal := range config .NotifyContainers {
149- log .Printf ("Sending container '%s' signal '%v'" , container , signal )
150- killOpts := docker.KillContainerOptions {
151- ID : container ,
152- Signal : signal ,
153- }
154- if err := client .KillContainer (killOpts ); err != nil {
155- log .Printf ("Error sending signal to container: %s" , err )
156- }
157- }
158- }
159-
16072func loadConfig (file string ) error {
16173 _ , err := toml .DecodeFile (file , & configs )
16274 if err != nil {
@@ -165,126 +77,6 @@ func loadConfig(file string) error {
16577 return nil
16678}
16779
168- func generateAtInterval (client * docker.Client , configs dockergen.ConfigFile ) {
169- for _ , config := range configs .Config {
170-
171- if config .Interval == 0 {
172- continue
173- }
174-
175- log .Printf ("Generating every %d seconds" , config .Interval )
176- wg .Add (1 )
177- ticker := time .NewTicker (time .Duration (config .Interval ) * time .Second )
178- quit := make (chan struct {})
179- configCopy := config
180- go func () {
181- defer wg .Done ()
182- for {
183- select {
184- case <- ticker .C :
185- containers , err := dockergen .GetContainers (client )
186- if err != nil {
187- log .Printf ("Error listing containers: %s\n " , err )
188- continue
189- }
190- // ignore changed return value. always run notify command
191- dockergen .GenerateFile (configCopy , containers )
192- runNotifyCmd (configCopy )
193- sendSignalToContainer (client , configCopy )
194- case <- quit :
195- ticker .Stop ()
196- return
197- }
198- }
199- }()
200- }
201- }
202-
203- func generateFromEvents (client * docker.Client , configs dockergen.ConfigFile ) {
204- configs = configs .FilterWatches ()
205- if len (configs .Config ) == 0 {
206- return
207- }
208-
209- wg .Add (1 )
210- defer wg .Done ()
211-
212- for {
213- if client == nil {
214- var err error
215- endpoint , err := dockergen .GetEndpoint (endpoint )
216- if err != nil {
217- log .Printf ("Bad endpoint: %s" , err )
218- time .Sleep (10 * time .Second )
219- continue
220- }
221-
222- client , err = NewDockerClient (endpoint )
223- if err != nil {
224- log .Printf ("Unable to connect to docker daemon: %s" , err )
225- time .Sleep (10 * time .Second )
226- continue
227- }
228- generateFromContainers (client )
229- }
230-
231- eventChan := make (chan * docker.APIEvents , 100 )
232- defer close (eventChan )
233-
234- watching := false
235- for {
236-
237- if client == nil {
238- break
239- }
240- err := client .Ping ()
241- if err != nil {
242- log .Printf ("Unable to ping docker daemon: %s" , err )
243- if watching {
244- client .RemoveEventListener (eventChan )
245- watching = false
246- client = nil
247- }
248- time .Sleep (10 * time .Second )
249- break
250-
251- }
252-
253- if ! watching {
254- err = client .AddEventListener (eventChan )
255- if err != nil && err != docker .ErrListenerAlreadyExists {
256- log .Printf ("Error registering docker event listener: %s" , err )
257- time .Sleep (10 * time .Second )
258- continue
259- }
260- watching = true
261- log .Println ("Watching docker events" )
262- }
263-
264- select {
265-
266- case event := <- eventChan :
267- if event == nil {
268- if watching {
269- client .RemoveEventListener (eventChan )
270- watching = false
271- client = nil
272- }
273- break
274- }
275-
276- if event .Status == "start" || event .Status == "stop" || event .Status == "die" {
277- log .Printf ("Received event %s for container %s" , event .Status , event .ID [:12 ])
278- generateFromContainers (client )
279- }
280- case <- time .After (10 * time .Second ):
281- // check for docker liveness
282- }
283-
284- }
285- }
286- }
287-
28880func initFlags () {
28981
29082 certPath := filepath .Join (os .Getenv ("DOCKER_CERT_PATH" ))
@@ -354,30 +146,20 @@ func main() {
354146 Config : []dockergen.Config {config }}
355147 }
356148
357- endpoint , err := dockergen .GetEndpoint (endpoint )
358- if err != nil {
359- log .Fatalf ("Bad endpoint: %s" , err )
360- }
149+ generator , err := dockergen .NewGenerator (dockergen.GeneratorConfig {
150+ Endpoint : endpoint ,
151+ TLSKey : tlsKey ,
152+ TLSCert : tlsCert ,
153+ TLSCACert : tlsCaCert ,
154+ TLSVerify : tlsVerify ,
155+ ConfigFile : configs ,
156+ })
361157
362- client , err := NewDockerClient (endpoint )
363158 if err != nil {
364- log .Fatalf ("Unable to create docker client : %s " , err )
159+ log .Fatalf ("error creating generator : %v " , err )
365160 }
366161
367- generateFromContainers (client )
368- generateAtInterval (client , configs )
369- generateFromEvents (client , configs )
370- wg .Wait ()
371- }
372-
373- // pathExists returns whether the given file or directory exists or not
374- func pathExists (path string ) (bool , error ) {
375- _ , err := os .Stat (path )
376- if err == nil {
377- return true , nil
378- }
379- if os .IsNotExist (err ) {
380- return false , nil
162+ if err := generator .Generate (); err != nil {
163+ log .Fatalf ("error running generate: %v" , err )
381164 }
382- return false , err
383165}
0 commit comments