Skip to content

Commit

Permalink
Merge pull request #19 from lucaslorentz/docker-events
Browse files Browse the repository at this point in the history
Listen to docker events and allow fallback to other caddy loaders
  • Loading branch information
lucaslorentz authored Mar 13, 2018
2 parents a48078e + 67cac6b commit e212db9
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 33 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
caddy
caddy.exe
vendor
debug.test
debug.test
Caddyfile
20 changes: 2 additions & 18 deletions plugin/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,12 @@ import (
"github.com/docker/docker/client"
)

var dockerClient *client.Client
var suffixRegex = regexp.MustCompile("_\\d+$")

// GenerateCaddyFile generates a caddy file config from docker swarm
func GenerateCaddyFile() []byte {
func GenerateCaddyFile(dockerClient *client.Client) []byte {
var buffer bytes.Buffer

if dockerClient == nil {
var err error
if dockerClient, err = client.NewEnvClient(); err != nil {
addError(&buffer, err)
return buffer.Bytes()
}

dockerPing, err := dockerClient.Ping(context.Background())
if err != nil {
addError(&buffer, err)
return buffer.Bytes()
}

dockerClient.NegotiateAPIVersionPing(dockerPing)
}

containers, err := dockerClient.ContainerList(context.Background(), types.ContainerListOptions{})
if err == nil {
for _, container := range containers {
Expand Down Expand Up @@ -71,6 +54,7 @@ func addError(buffer *bytes.Buffer, e error) {

func addContainerToCaddyFile(buffer *bytes.Buffer, container *types.Container) {
ipAddress := getContainerIPAddress(container)

var directives = parseDirectives(container.Labels, container, ipAddress)
for _, name := range getSortedKeys(&directives.children) {
writeDirective(buffer, directives.children[name], 0)
Expand Down
91 changes: 77 additions & 14 deletions plugin/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@ package plugin

import (
"bytes"
"context"
"log"
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/mholt/caddy"
)

const poolInterval = 10 * time.Second

// DockerLoader generates caddy files from docker swarm information
type DockerLoader struct {
Input caddy.CaddyfileInput
Initialized bool
initialized bool
dockerClient *client.Client
timer *time.Timer
skipEvents bool
Input caddy.CaddyfileInput
}

// CreateDockerLoader creates a docker loader
Expand All @@ -28,25 +37,75 @@ func (dockerLoader *DockerLoader) Load(serverType string) (caddy.Input, error) {
if serverType != "http" {
return nil, nil
}
if !dockerLoader.Initialized {
dockerLoader.Initialized = true
dockerLoader.updateInput()
dockerLoader.scheduleUpdate()
if !dockerLoader.initialized {
dockerLoader.initialized = true

dockerClient, err := client.NewEnvClient()
if err != nil {
log.Printf("Docker connection failed: %v", err)
return nil, nil
}

dockerPing, err := dockerClient.Ping(context.Background())
if err != nil {
log.Printf("Docker ping failed: %v", err)
return nil, nil
}

dockerClient.NegotiateAPIVersionPing(dockerPing)

dockerLoader.dockerClient = dockerClient

dockerLoader.timer = time.AfterFunc(poolInterval, func() {
dockerLoader.update(true)
})

dockerLoader.update(false)

go dockerLoader.monitorEvents()
}
return dockerLoader.Input, nil
}

func (dockerLoader *DockerLoader) scheduleUpdate() {
time.AfterFunc(10*time.Second, func() {
if dockerLoader.updateInput() {
ReloadCaddy()
}
dockerLoader.scheduleUpdate()
func (dockerLoader *DockerLoader) monitorEvents() {
args := filters.NewArgs()
args.Add("scope", "swarm")
args.Add("scope", "local")
args.Add("type", "service")
args.Add("type", "container")

eventsChan, errorChan := dockerLoader.dockerClient.Events(context.Background(), types.EventsOptions{
Filters: args,
})

for {
select {
case event := <-eventsChan:
if dockerLoader.skipEvents {
continue
}

update := (event.Type == "container" && event.Action == "start") ||
(event.Type == "container" && event.Action == "stop") ||
(event.Type == "service" && event.Action == "create") ||
(event.Type == "service" && event.Action == "update") ||
(event.Type == "service" && event.Action == "remove")

if update {
dockerLoader.skipEvents = true
dockerLoader.timer.Reset(100 * time.Millisecond)
}
case err := <-errorChan:
log.Println(err)
}
}
}

func (dockerLoader *DockerLoader) updateInput() bool {
newContents := GenerateCaddyFile()
func (dockerLoader *DockerLoader) update(reloadIfChanged bool) bool {
dockerLoader.timer.Reset(poolInterval)
dockerLoader.skipEvents = false

newContents := GenerateCaddyFile(dockerLoader.dockerClient)

if bytes.Equal(dockerLoader.Input.Contents, newContents) {
return false
Expand All @@ -56,5 +115,9 @@ func (dockerLoader *DockerLoader) updateInput() bool {

log.Printf("[INFO] New CaddyFile:\n%s", dockerLoader.Input.Contents)

if reloadIfChanged {
ReloadCaddy()
}

return true
}

0 comments on commit e212db9

Please sign in to comment.