add volume events and fix repeated keys in configuration
parent
099c635aa7
commit
d4c645cc55
|
@ -17,6 +17,8 @@ func Make(message dockerEvents.Message, client *client.Client) Event {
|
|||
return makeContainer(message, client)
|
||||
case "network":
|
||||
return makeNetwork(message, client)
|
||||
case "volume":
|
||||
return makeVolume(message, client)
|
||||
default:
|
||||
log.Printf("unknown event type %v", message.Type)
|
||||
return nil
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/docker/docker/api/types"
|
||||
dockerEvents "github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/client"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Volume struct {
|
||||
Action string
|
||||
ID string
|
||||
Destination *string
|
||||
Volume *types.Volume
|
||||
Container *types.ContainerJSON
|
||||
}
|
||||
|
||||
//goland:noinspection ALL
|
||||
func (c Volume) __interface_event() {
|
||||
panic("interface event guard")
|
||||
}
|
||||
|
||||
func makeVolume(message dockerEvents.Message, client *client.Client) Event {
|
||||
var e Volume
|
||||
e.ID = message.Actor.ID
|
||||
e.Action = message.Action
|
||||
|
||||
if message.Action != "destroy" {
|
||||
volume, err := client.VolumeInspect(context.TODO(), message.Actor.ID)
|
||||
if err != nil {
|
||||
log.Printf("error inspecting volume %v: %v", message.Actor.ID, err)
|
||||
} else {
|
||||
e.Volume = &volume
|
||||
}
|
||||
}
|
||||
|
||||
if message.Action == "mount" || message.Action == "unmount" {
|
||||
if containerId, ok := message.Actor.Attributes["container"]; ok {
|
||||
container, err := client.ContainerInspect(context.TODO(), containerId)
|
||||
if err != nil {
|
||||
log.Printf("error inspecting container %v: %v", containerId, err)
|
||||
} else {
|
||||
e.Container = &container
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if message.Action == "mount" {
|
||||
if dest, ok := message.Actor.Attributes["destination"]; ok {
|
||||
e.Destination = &dest
|
||||
}
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
13
example.conf
13
example.conf
|
@ -1,12 +1,9 @@
|
|||
|
||||
[Container]
|
||||
Action=start
|
||||
Run=notify-send "{{ .Container.Name }}"
|
||||
Run=notify-send "container {{ .Action }}: {{ .ID }}"
|
||||
|
||||
[Network]
|
||||
Action=connect
|
||||
Run=notify-send "connected container {{ .Container.Name }} to network {{ .Network.Name }}"
|
||||
Run=notify-send "network {{ .Action }} {{ .ID }}"
|
||||
|
||||
[Network]
|
||||
Action=disconnect
|
||||
Run=notify-send "disconnected container {{ .Container.Name }} from network {{ .Network.Name }}"
|
||||
[Volume]
|
||||
Name=foo*
|
||||
Run=notify-send "volume {{ .Action }} {{ .ID }}"
|
||||
|
|
|
@ -65,41 +65,43 @@ func readContainerFromConfig(section *ini.Section) (Container, error) {
|
|||
var err error
|
||||
handler.Label = make(map[string]*string)
|
||||
for _, key := range section.Keys() {
|
||||
val := key.String()
|
||||
values := key.ValueWithShadows()
|
||||
switch key.Name() {
|
||||
case "Action":
|
||||
handler.Action = append(handler.Action, val)
|
||||
handler.Action = values
|
||||
break
|
||||
case "Name":
|
||||
handler.Name = append(handler.Name, val)
|
||||
handler.Name = values
|
||||
break
|
||||
case "Image":
|
||||
handler.Image = append(handler.Image, val)
|
||||
handler.Image = values
|
||||
break
|
||||
case "ID":
|
||||
handler.ID = append(handler.ID, val)
|
||||
handler.ID = values
|
||||
break
|
||||
case "Hostname":
|
||||
handler.Hostname = append(handler.Hostname, val)
|
||||
handler.Hostname = values
|
||||
break
|
||||
case "Label":
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
var k string
|
||||
var v *string
|
||||
if len(parts) == 2 {
|
||||
k = parts[0]
|
||||
v = &parts[1]
|
||||
} else {
|
||||
k = parts[0]
|
||||
v = nil
|
||||
for _, val := range values {
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
var k string
|
||||
var v *string
|
||||
if len(parts) == 2 {
|
||||
k = parts[0]
|
||||
v = &parts[1]
|
||||
} else {
|
||||
k = parts[0]
|
||||
v = nil
|
||||
}
|
||||
handler.Label[k] = v
|
||||
}
|
||||
handler.Label[k] = v
|
||||
break
|
||||
case "Run":
|
||||
if handler.Run != nil {
|
||||
if len(values) > 1 {
|
||||
return handler, errors.New(fmt.Sprintf("duplicate key %v in section %v", key.Name(), section.Name()))
|
||||
}
|
||||
handler.Run, err = template.New("Run").Parse(val)
|
||||
handler.Run, err = template.New("Run").Parse(values[0])
|
||||
if err != nil {
|
||||
return handler, err
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ func ReadFromConfig(section *ini.Section) (Handler, error) {
|
|||
return readContainerFromConfig(section)
|
||||
case "Network":
|
||||
return readNetworkFromConfig(section)
|
||||
case "Volume":
|
||||
return readVolumeFromConfig(section)
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("unknown section %v", section.Name()))
|
||||
}
|
||||
|
|
|
@ -89,64 +89,68 @@ func readNetworkFromConfig(section *ini.Section) (Network, error) {
|
|||
handler.Label = make(map[string]*string)
|
||||
handler.ContainerLabel = make(map[string]*string)
|
||||
for _, key := range section.Keys() {
|
||||
val := key.String()
|
||||
values := key.ValueWithShadows()
|
||||
switch key.Name() {
|
||||
case "Action":
|
||||
handler.Action = append(handler.Action, val)
|
||||
handler.Action = values
|
||||
break
|
||||
case "Name":
|
||||
handler.Name = append(handler.Name, val)
|
||||
handler.Name = values
|
||||
break
|
||||
case "ID":
|
||||
handler.ID = append(handler.ID, val)
|
||||
handler.ID = values
|
||||
break
|
||||
case "Driver":
|
||||
handler.Driver = append(handler.Driver, val)
|
||||
handler.Driver = values
|
||||
break
|
||||
case "Label":
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
var k string
|
||||
var v *string
|
||||
if len(parts) == 2 {
|
||||
k = parts[0]
|
||||
v = &parts[1]
|
||||
} else {
|
||||
k = parts[0]
|
||||
v = nil
|
||||
for _, val := range values {
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
var k string
|
||||
var v *string
|
||||
if len(parts) == 2 {
|
||||
k = parts[0]
|
||||
v = &parts[1]
|
||||
} else {
|
||||
k = parts[0]
|
||||
v = nil
|
||||
}
|
||||
handler.Label[k] = v
|
||||
}
|
||||
handler.Label[k] = v
|
||||
break
|
||||
|
||||
case "ContainerName":
|
||||
handler.ContainerName = append(handler.ContainerName, val)
|
||||
handler.ContainerName = values
|
||||
break
|
||||
case "ContainerID":
|
||||
handler.ContainerID = append(handler.ContainerID, val)
|
||||
handler.ContainerID = values
|
||||
break
|
||||
case "ContainerImage":
|
||||
handler.ContainerImage = append(handler.ContainerImage, val)
|
||||
handler.ContainerImage = values
|
||||
break
|
||||
case "ContainerHostname":
|
||||
handler.ContainerHostname = append(handler.ContainerHostname, val)
|
||||
handler.ContainerHostname = values
|
||||
break
|
||||
case "ContainerLabel":
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
var k string
|
||||
var v *string
|
||||
if len(parts) == 2 {
|
||||
k = parts[0]
|
||||
v = &parts[1]
|
||||
} else {
|
||||
k = parts[0]
|
||||
v = nil
|
||||
for _, val := range values {
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
var k string
|
||||
var v *string
|
||||
if len(parts) == 2 {
|
||||
k = parts[0]
|
||||
v = &parts[1]
|
||||
} else {
|
||||
k = parts[0]
|
||||
v = nil
|
||||
}
|
||||
handler.ContainerLabel[k] = v
|
||||
}
|
||||
handler.ContainerLabel[k] = v
|
||||
break
|
||||
case "Run":
|
||||
if handler.Run != nil {
|
||||
if len(values) > 1 {
|
||||
return handler, errors.New(fmt.Sprintf("duplicate key %v in section %v", key.Name(), section.Name()))
|
||||
}
|
||||
handler.Run, err = template.New("Run").Parse(val)
|
||||
handler.Run, err = template.New("Run").Parse(values[0])
|
||||
if err != nil {
|
||||
return handler, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"docker-event-handler/events"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gopkg.in/ini.v1"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type Volume struct {
|
||||
Action []string
|
||||
Name []string
|
||||
Driver []string
|
||||
Destination []string
|
||||
ID []string
|
||||
Label map[string]*string
|
||||
ContainerName []string
|
||||
ContainerImage []string
|
||||
ContainerID []string
|
||||
ContainerHostname []string
|
||||
ContainerLabel map[string]*string
|
||||
Run *template.Template
|
||||
}
|
||||
|
||||
func (h Volume) Matches(event events.Event) bool {
|
||||
e, ok := event.(events.Volume)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if !stringListMatches(h.Action, e.Action) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !stringListMatches(h.ID, e.ID) {
|
||||
return false
|
||||
}
|
||||
|
||||
if e.Volume == nil {
|
||||
if len(h.Name) > 0 || len(h.Driver) > 0 || len(h.Label) > 0 {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if !stringListMatches(h.Name, e.Volume.Name) {
|
||||
return false
|
||||
}
|
||||
if !stringListMatches(h.Driver, e.Volume.Driver) {
|
||||
return false
|
||||
}
|
||||
if !labelsMatch(h.Label, e.Volume.Labels) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if e.Destination == nil {
|
||||
if len(h.Destination) > 0 {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if !stringListMatches(h.Destination, *e.Destination) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if e.Container == nil {
|
||||
if len(h.ContainerID) > 0 || len(h.ContainerName) > 0 || len(h.ContainerImage) > 0 || len(h.ContainerHostname) > 0 || len(h.ContainerLabel) > 0 {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if !stringListMatches(h.ContainerID, e.Container.ID) {
|
||||
return false
|
||||
}
|
||||
if !stringListMatches(h.ContainerName, e.Container.Name) {
|
||||
return false
|
||||
}
|
||||
if !stringListMatches(h.ContainerImage, e.Container.Image) {
|
||||
return false
|
||||
}
|
||||
if !stringListMatches(h.ContainerHostname, e.Container.Config.Hostname) {
|
||||
return false
|
||||
}
|
||||
if !labelsMatch(h.ContainerLabel, e.Container.Config.Labels) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (h Volume) Invoke(event events.Event) error {
|
||||
e := event.(events.Volume) // enforce that the event is a volume event
|
||||
return runTemplatedScript(h.Run, e)
|
||||
}
|
||||
|
||||
func readVolumeFromConfig(section *ini.Section) (Volume, error) {
|
||||
var handler Volume
|
||||
var err error
|
||||
handler.Label = make(map[string]*string)
|
||||
handler.ContainerLabel = make(map[string]*string)
|
||||
for _, key := range section.Keys() {
|
||||
values := key.ValueWithShadows()
|
||||
switch key.Name() {
|
||||
case "Action":
|
||||
handler.Action = values
|
||||
break
|
||||
case "Name":
|
||||
handler.Name = values
|
||||
break
|
||||
case "ID":
|
||||
handler.ID = values
|
||||
break
|
||||
case "Driver":
|
||||
handler.Driver = values
|
||||
break
|
||||
case "Destination":
|
||||
handler.Destination = values
|
||||
break
|
||||
case "Label":
|
||||
for _, val := range values {
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
var k string
|
||||
var v *string
|
||||
if len(parts) == 2 {
|
||||
k = parts[0]
|
||||
v = &parts[1]
|
||||
} else {
|
||||
k = parts[0]
|
||||
v = nil
|
||||
}
|
||||
handler.Label[k] = v
|
||||
}
|
||||
break
|
||||
|
||||
case "ContainerName":
|
||||
handler.ContainerName = values
|
||||
break
|
||||
case "ContainerID":
|
||||
handler.ContainerID = values
|
||||
break
|
||||
case "ContainerImage":
|
||||
handler.ContainerImage = values
|
||||
break
|
||||
case "ContainerHostname":
|
||||
handler.ContainerHostname = values
|
||||
break
|
||||
case "ContainerLabel":
|
||||
for _, val := range values {
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
var k string
|
||||
var v *string
|
||||
if len(parts) == 2 {
|
||||
k = parts[0]
|
||||
v = &parts[1]
|
||||
} else {
|
||||
k = parts[0]
|
||||
v = nil
|
||||
}
|
||||
handler.ContainerLabel[k] = v
|
||||
}
|
||||
break
|
||||
case "Run":
|
||||
if len(values) > 1 {
|
||||
return handler, errors.New(fmt.Sprintf("duplicate key %v in section %v", key.Name(), section.Name()))
|
||||
}
|
||||
handler.Run, err = template.New("Run").Parse(values[0])
|
||||
if err != nil {
|
||||
return handler, err
|
||||
}
|
||||
break
|
||||
default:
|
||||
return handler, errors.New(fmt.Sprintf("unknown key %v in section %v", key.Name(), section.Name()))
|
||||
}
|
||||
}
|
||||
return handler, nil
|
||||
}
|
Loading…
Reference in New Issue