diff --git a/README.md b/README.md index 14f93821..6bb2cc1e 100644 --- a/README.md +++ b/README.md @@ -101,9 +101,14 @@ Options: log the output(stdout/stderr) of notify command -notify-container container-ID container to send a signal to + -notify-filter key=value + container filter for notification (e.g -notify-filter name=foo). + You can have multiple of these. + https://docs.docker.com/engine/reference/commandline/ps/#filter -notify-signal signal - signal to send to the -notify-container. -1 to call docker restart. Defaults to 1 aka. HUP. - All available signals available on the [dockerclient](https://github.com/fsouza/go-dockerclient/blob/01804dec8a84d0a77e63611f2b62d33e9bb2b64a/signal.go) + signal to send to the -notify-container and -notify-filter. -1 to call docker restart. Defaults to 1 aka. HUP. + All available signals available on the dockerclient + https://github.com/fsouza/go-dockerclient/blob/01804dec8a84d0a77e63611f2b62d33e9bb2b64a/signal.go -notify-sighup container-ID send HUP signal to container. Equivalent to 'docker kill -s HUP container-ID', or `-notify-container container-ID -notify-signal 1` -only-exposed diff --git a/cmd/docker-gen/main.go b/cmd/docker-gen/main.go index 612dc895..019bf0fb 100644 --- a/cmd/docker-gen/main.go +++ b/cmd/docker-gen/main.go @@ -7,6 +7,7 @@ import ( "os" "os/signal" "path/filepath" + "strings" "syscall" "github.com/BurntSushi/toml" @@ -16,6 +17,7 @@ import ( ) type stringslice []string +type mapstringslice map[string][]string var ( buildVersion string @@ -26,6 +28,7 @@ var ( notifyOutput bool notifyContainerID string notifyContainerSignal int + notifyContainerFilter mapstringslice = make(mapstringslice) onlyExposed bool onlyPublished bool includeStopped bool @@ -50,6 +53,18 @@ func (strings *stringslice) Set(value string) error { return nil } +func (filter *mapstringslice) String() string { + return "[string][]string" +} + +func (filter *mapstringslice) Set(value string) error { + name, value, found := strings.Cut(value, "=") + if found { + (*filter)[name] = append((*filter)[name], value) + } + return nil +} + func usage() { println(`Usage: docker-gen [options] template [dest] @@ -100,8 +115,10 @@ func initFlags() { "send HUP signal to container. Equivalent to docker kill -s HUP `container-ID`") flag.StringVar(¬ifyContainerID, "notify-container", "", "container to send a signal to") + flag.Var(¬ifyContainerFilter, "notify-filter", + "container filter for notification (e.g -notify-filter name=foo). You can have multiple of these. https://docs.docker.com/engine/reference/commandline/ps/#filter") flag.IntVar(¬ifyContainerSignal, "notify-signal", int(docker.SIGHUP), - "signal to send to the notify-container. Defaults to SIGHUP") + "signal to send to the notify-container and notify-filter. Defaults to SIGHUP") flag.Var(&configFiles, "config", "config files with template directives. Config files will be merged if this option is specified multiple times.") flag.IntVar(&interval, "interval", 0, "notify command interval (secs)") flag.BoolVar(&keepBlankLines, "keep-blank-lines", false, "keep blank lines in the output file") @@ -161,6 +178,10 @@ func main() { if notifyContainerID != "" { cfg.NotifyContainers[notifyContainerID] = notifyContainerSignal } + if len(notifyContainerFilter) > 0 { + cfg.NotifyContainersFilter = notifyContainerFilter + cfg.NotifyContainersSignal = notifyContainerSignal + } configs = config.ConfigFile{ Config: []config.Config{cfg}} } diff --git a/internal/config/config.go b/internal/config/config.go index 03403022..38ac223c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -7,18 +7,20 @@ import ( ) type Config struct { - Template string - Dest string - Watch bool - Wait *Wait - NotifyCmd string - NotifyOutput bool - NotifyContainers map[string]int - OnlyExposed bool - OnlyPublished bool - IncludeStopped bool - Interval int - KeepBlankLines bool + Template string + Dest string + Watch bool + Wait *Wait + NotifyCmd string + NotifyOutput bool + NotifyContainers map[string]int + NotifyContainersFilter map[string][]string + NotifyContainersSignal int + OnlyExposed bool + OnlyPublished bool + IncludeStopped bool + Interval int + KeepBlankLines bool } type ConfigFile struct { diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 6d5cb15e..542e7445 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -132,7 +132,8 @@ func (g *generator) generateFromContainers() { continue } g.runNotifyCmd(config) - g.sendSignalToContainer(config) + g.sendSignalToContainers(config) + g.sendSignalToFilteredContainers(config) } } @@ -162,7 +163,8 @@ func (g *generator) generateAtInterval() { // ignore changed return value. always run notify command template.GenerateFile(cfg, containers) g.runNotifyCmd(cfg) - g.sendSignalToContainer(cfg) + g.sendSignalToContainers(cfg) + g.sendSignalToFilteredContainers(cfg) case sig := <-sigChan: log.Printf("Received signal: %s\n", sig) switch sig { @@ -210,7 +212,8 @@ func (g *generator) generateFromEvents() { continue } g.runNotifyCmd(cfg) - g.sendSignalToContainer(cfg) + g.sendSignalToContainers(cfg) + g.sendSignalToFilteredContainers(cfg) } }(cfg) } @@ -332,28 +335,50 @@ func (g *generator) runNotifyCmd(config config.Config) { } } -func (g *generator) sendSignalToContainer(config config.Config) { +func (g *generator) sendSignalToContainer(container string, signal int) { + log.Printf("Sending container '%s' signal '%v'", container, signal) + + if signal == -1 { + if err := g.Client.RestartContainer(container, 10); err != nil { + log.Printf("Error sending restarting container: %s", err) + } + return + } + + killOpts := docker.KillContainerOptions{ + ID: container, + Signal: docker.Signal(signal), + } + if err := g.Client.KillContainer(killOpts); err != nil { + log.Printf("Error sending signal to container: %s", err) + } +} + +func (g *generator) sendSignalToContainers(config config.Config) { if len(config.NotifyContainers) < 1 { return } for container, signal := range config.NotifyContainers { - log.Printf("Sending container '%s' signal '%v'", container, signal) + g.sendSignalToContainer(container, signal) + } +} - if signal == -1 { - if err := g.Client.RestartContainer(container, 10); err != nil { - log.Printf("Error sending restarting container: %s", err) - } - return - } +func (g *generator) sendSignalToFilteredContainers(config config.Config) { + if len(config.NotifyContainersFilter) < 1 { + return + } - killOpts := docker.KillContainerOptions{ - ID: container, - Signal: docker.Signal(signal), - } - if err := g.Client.KillContainer(killOpts); err != nil { - log.Printf("Error sending signal to container: %s", err) - } + containers, err := g.Client.ListContainers(docker.ListContainersOptions{ + Filters: config.NotifyContainersFilter, + }) + if err != nil { + log.Printf("Error getting containers: %s", err) + return + } + + for _, container := range containers { + g.sendSignalToContainer(container.ID, config.NotifyContainersSignal) } }