Migrate traefik to engine-api

The docker provider now uses docker/engine-api and
vdemeester/docker-events instead of fsouza-dockerclient.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
Vincent Demeester 2016-04-08 14:20:54 +02:00
parent f6564909aa
commit 866b9835a6
No known key found for this signature in database
GPG key ID: 083CC6FD6EB699A3
4 changed files with 387 additions and 232 deletions

37
glide.lock generated
View file

@ -1,5 +1,5 @@
hash: 2e15595ec349ec462fa2b0a52e26e3f3dcbd17fed66dad9a1e1c2e2c0385fe49 hash: 79b6eb2a613b5e2ce5c57150eec41ac04def3f232a3613fd8b5a88b5e1041b38
updated: 2016-04-02T15:25:37.354420171+02:00 updated: 2016-04-02T15:42:37.505896092+02:00
imports: imports:
- name: github.com/alecthomas/template - name: github.com/alecthomas/template
version: b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0 version: b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0
@ -89,10 +89,18 @@ imports:
- types/container - types/container
- types/filters - types/filters
- types/strslice - types/strslice
- client/transport
- client/transport/cancellable
- types/network
- types/registry
- types/time
- types/blkiodev
- name: github.com/docker/go-connections - name: github.com/docker/go-connections
version: f549a9393d05688dff0992ef3efd8bbe6c628aeb version: f549a9393d05688dff0992ef3efd8bbe6c628aeb
subpackages: subpackages:
- nat - nat
- sockets
- tlsconfig
- name: github.com/docker/go-units - name: github.com/docker/go-units
version: 5d2041e26a699eaca682e2ea41c8f891e1060444 version: 5d2041e26a699eaca682e2ea41c8f891e1060444
- name: github.com/docker/libcompose - name: github.com/docker/libcompose
@ -113,26 +121,6 @@ imports:
version: d5cac425555ca5cf00694df246e04f05e6a55150 version: d5cac425555ca5cf00694df246e04f05e6a55150
- name: github.com/flynn/go-shlex - name: github.com/flynn/go-shlex
version: 3f9db97f856818214da2e1057f8ad84803971cff version: 3f9db97f856818214da2e1057f8ad84803971cff
- name: github.com/fsouza/go-dockerclient
version: a49c8269a6899cae30da1f8a4b82e0ce945f9967
subpackages:
- external/github.com/docker/docker/opts
- external/github.com/docker/docker/pkg/archive
- external/github.com/docker/docker/pkg/fileutils
- external/github.com/docker/docker/pkg/homedir
- external/github.com/docker/docker/pkg/stdcopy
- external/github.com/hashicorp/go-cleanhttp
- external/github.com/Sirupsen/logrus
- external/github.com/docker/docker/pkg/idtools
- external/github.com/docker/docker/pkg/ioutils
- external/github.com/docker/docker/pkg/longpath
- external/github.com/docker/docker/pkg/pools
- external/github.com/docker/docker/pkg/promise
- external/github.com/docker/docker/pkg/system
- external/github.com/opencontainers/runc/libcontainer/user
- external/golang.org/x/sys/unix
- external/golang.org/x/net/context
- external/github.com/docker/go-units
- name: github.com/gambol99/go-marathon - name: github.com/gambol99/go-marathon
version: ade11d1dc2884ee1f387078fc28509559b6235d1 version: ade11d1dc2884ee1f387078fc28509559b6235d1
- name: github.com/go-check/check - name: github.com/go-check/check
@ -182,6 +170,8 @@ imports:
version: 565402cd71fbd9c12aa7e295324ea357e970a61e version: 565402cd71fbd9c12aa7e295324ea357e970a61e
- name: github.com/mailgun/timetools - name: github.com/mailgun/timetools
version: fd192d755b00c968d312d23f521eb0cdc6f66bd0 version: fd192d755b00c968d312d23f521eb0cdc6f66bd0
- name: github.com/Microsoft/go-winio
version: 9e2895e5f6c3f16473b91d37fae6e89990a4520c
- name: github.com/miekg/dns - name: github.com/miekg/dns
version: 7e024ce8ce18b21b475ac6baf8fa3c42536bf2fa version: 7e024ce8ce18b21b475ac6baf8fa3c42536bf2fa
- name: github.com/mitchellh/mapstructure - name: github.com/mitchellh/mapstructure
@ -223,6 +213,8 @@ imports:
version: 54ed61c2b47e263ae2f01b86837b0c4bd1da28e8 version: 54ed61c2b47e263ae2f01b86837b0c4bd1da28e8
- name: github.com/unrolled/render - name: github.com/unrolled/render
version: 26b4e3aac686940fe29521545afad9966ddfc80c version: 26b4e3aac686940fe29521545afad9966ddfc80c
- name: github.com/vdemeester/docker-events
version: bd72e1848b08db4b5ed1a2e9277621b9f5e5d1f3
- name: github.com/vdemeester/libkermit - name: github.com/vdemeester/libkermit
version: 7e4e689a6fa9281e0fb9b7b9c297e22d5342a5ec version: 7e4e689a6fa9281e0fb9b7b9c297e22d5342a5ec
- name: github.com/vdemeester/shakers - name: github.com/vdemeester/shakers
@ -257,6 +249,7 @@ imports:
subpackages: subpackages:
- context - context
- publicsuffix - publicsuffix
- proxy
- name: golang.org/x/sys - name: golang.org/x/sys
version: eb2c74142fd19a79b3f237334c7384d5167b1b46 version: eb2c74142fd19a79b3f237334c7384d5167b1b46
subpackages: subpackages:

View file

@ -52,8 +52,6 @@ import:
ref: 26b4e3aac686940fe29521545afad9966ddfc80c ref: 26b4e3aac686940fe29521545afad9966ddfc80c
- package: github.com/flynn/go-shlex - package: github.com/flynn/go-shlex
ref: 3f9db97f856818214da2e1057f8ad84803971cff ref: 3f9db97f856818214da2e1057f8ad84803971cff
- package: github.com/fsouza/go-dockerclient
ref: a49c8269a6899cae30da1f8a4b82e0ce945f9967
- package: github.com/boltdb/bolt - package: github.com/boltdb/bolt
ref: 51f99c862475898df9773747d3accd05a7ca33c1 ref: 51f99c862475898df9773747d3accd05a7ca33c1
- package: gopkg.in/mgo.v2 - package: gopkg.in/mgo.v2
@ -168,8 +166,11 @@ import:
- types/container - types/container
- types/filters - types/filters
- types/strslice - types/strslice
- package: github.com/vdemeester/docker-events
- package: github.com/docker/go-connections - package: github.com/docker/go-connections
subpackages: subpackages:
- nat - nat
- sockets
- tlsconfig
- package: github.com/docker/go-units - package: github.com/docker/go-units
- package: github.com/mailgun/multibuf - package: github.com/mailgun/multibuf

View file

@ -2,19 +2,31 @@ package provider
import ( import (
"errors" "errors"
"net/http"
"strconv" "strconv"
"strings" "strings"
"text/template" "text/template"
"time" "time"
"golang.org/x/net/context"
"github.com/BurntSushi/ty/fun" "github.com/BurntSushi/ty/fun"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/cenkalti/backoff" "github.com/cenkalti/backoff"
"github.com/containous/traefik/safe" "github.com/containous/traefik/safe"
"github.com/containous/traefik/types" "github.com/containous/traefik/types"
"github.com/fsouza/go-dockerclient" "github.com/docker/engine-api/client"
dockertypes "github.com/docker/engine-api/types"
eventtypes "github.com/docker/engine-api/types/events"
"github.com/docker/engine-api/types/filters"
"github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig"
"github.com/vdemeester/docker-events"
) )
// DockerAPIVersion is a constant holding the version of the Docker API traefik will use
const DockerAPIVersion string = "1.21"
// Docker holds configurations of the Docker provider. // Docker holds configurations of the Docker provider.
type Docker struct { type Docker struct {
BaseProvider `mapstructure:",squash"` BaseProvider `mapstructure:",squash"`
@ -31,59 +43,94 @@ type DockerTLS struct {
InsecureSkipVerify bool InsecureSkipVerify bool
} }
func (provider *Docker) createClient() (client.APIClient, error) {
var httpClient *http.Client
httpHeaders := map[string]string{
// FIXME(vdemeester) use version here O:)
"User-Agent": "Traefik",
}
if provider.TLS != nil {
tlsOptions := tlsconfig.Options{
CAFile: provider.TLS.CA,
CertFile: provider.TLS.Cert,
KeyFile: provider.TLS.Key,
InsecureSkipVerify: provider.TLS.InsecureSkipVerify,
}
config, err := tlsconfig.Client(tlsOptions)
if err != nil {
return nil, err
}
tr := &http.Transport{
TLSClientConfig: config,
}
proto, addr, _, err := client.ParseHost(provider.Endpoint)
if err != nil {
return nil, err
}
sockets.ConfigureTransport(tr, proto, addr)
httpClient = &http.Client{
Transport: tr,
}
}
return client.NewClient(provider.Endpoint, DockerAPIVersion, httpClient, httpHeaders)
}
// Provide allows the provider to provide configurations to traefik // Provide allows the provider to provide configurations to traefik
// using the given configuration channel. // using the given configuration channel.
func (provider *Docker) Provide(configurationChan chan<- types.ConfigMessage) error { func (provider *Docker) Provide(configurationChan chan<- types.ConfigMessage) error {
safe.Go(func() { safe.Go(func() {
operation := func() error { operation := func() error {
var dockerClient *docker.Client
var err error var err error
if provider.TLS != nil { dockerClient, err := provider.createClient()
dockerClient, err = docker.NewTLSClient(provider.Endpoint,
provider.TLS.Cert, provider.TLS.Key, provider.TLS.CA)
if err == nil {
dockerClient.TLSConfig.InsecureSkipVerify = provider.TLS.InsecureSkipVerify
}
} else {
dockerClient, err = docker.NewClient(provider.Endpoint)
}
if err != nil { if err != nil {
log.Errorf("Failed to create a client for docker, error: %s", err) log.Errorf("Failed to create a client for docker, error: %s", err)
return err return err
} }
err = dockerClient.Ping() version, err := dockerClient.ServerVersion(context.Background())
log.Debugf("Docker connection established with docker %s (API %s)", version.Version, version.APIVersion)
containers, err := listContainers(dockerClient)
if err != nil { if err != nil {
log.Errorf("Docker connection error %+v", err) log.Errorf("Failed to list containers for docker, error %s", err)
return err return err
} }
log.Debug("Docker connection established") configuration := provider.loadDockerConfig(containers)
configuration := provider.loadDockerConfig(listContainers(dockerClient))
configurationChan <- types.ConfigMessage{ configurationChan <- types.ConfigMessage{
ProviderName: "docker", ProviderName: "docker",
Configuration: configuration, Configuration: configuration,
} }
if provider.Watch { if provider.Watch {
dockerEvents := make(chan *docker.APIEvents) ctx, cancel := context.WithCancel(context.Background())
dockerClient.AddEventListener(dockerEvents) f := filters.NewArgs()
log.Debug("Docker listening") f.Add("type", "container")
for { options := dockertypes.EventsOptions{
event := <-dockerEvents Filters: f,
if event == nil { }
return errors.New("Docker event nil") eventHandler := events.NewHandler(events.ByAction)
// log.Fatalf("Docker connection error") startStopHandle := func(m eventtypes.Message) {
log.Debugf("Docker event received %+v", m)
containers, err := listContainers(dockerClient)
if err != nil {
log.Errorf("Failed to list containers for docker, error %s", err)
// Call cancel to get out of the monitor
cancel()
} }
if event.Status == "start" || event.Status == "die" { configuration := provider.loadDockerConfig(containers)
log.Debugf("Docker event receveived %+v", event) if configuration != nil {
configuration := provider.loadDockerConfig(listContainers(dockerClient)) configurationChan <- types.ConfigMessage{
if configuration != nil { ProviderName: "docker",
configurationChan <- types.ConfigMessage{ Configuration: configuration,
ProviderName: "docker",
Configuration: configuration,
}
} }
} }
} }
eventHandler.Handle("start", startStopHandle)
eventHandler.Handle("die", startStopHandle)
errChan := events.MonitorWithHandler(ctx, dockerClient, options, eventHandler)
if err := <-errChan; err != nil {
return err
}
} }
return nil return nil
} }
@ -99,7 +146,7 @@ func (provider *Docker) Provide(configurationChan chan<- types.ConfigMessage) er
return nil return nil
} }
func (provider *Docker) loadDockerConfig(containersInspected []docker.Container) *types.Configuration { func (provider *Docker) loadDockerConfig(containersInspected []dockertypes.ContainerJSON) *types.Configuration {
var DockerFuncMap = template.FuncMap{ var DockerFuncMap = template.FuncMap{
"getBackend": provider.getBackend, "getBackend": provider.getBackend,
"getPort": provider.getPort, "getPort": provider.getPort,
@ -113,16 +160,16 @@ func (provider *Docker) loadDockerConfig(containersInspected []docker.Container)
} }
// filter containers // filter containers
filteredContainers := fun.Filter(containerFilter, containersInspected).([]docker.Container) filteredContainers := fun.Filter(containerFilter, containersInspected).([]dockertypes.ContainerJSON)
frontends := map[string][]docker.Container{} frontends := map[string][]dockertypes.ContainerJSON{}
for _, container := range filteredContainers { for _, container := range filteredContainers {
frontends[provider.getFrontendName(container)] = append(frontends[provider.getFrontendName(container)], container) frontends[provider.getFrontendName(container)] = append(frontends[provider.getFrontendName(container)], container)
} }
templateObjects := struct { templateObjects := struct {
Containers []docker.Container Containers []dockertypes.ContainerJSON
Frontends map[string][]docker.Container Frontends map[string][]dockertypes.ContainerJSON
Domain string Domain string
}{ }{
filteredContainers, filteredContainers,
@ -137,7 +184,7 @@ func (provider *Docker) loadDockerConfig(containersInspected []docker.Container)
return configuration return configuration
} }
func containerFilter(container docker.Container) bool { func containerFilter(container dockertypes.ContainerJSON) bool {
if len(container.NetworkSettings.Ports) == 0 { if len(container.NetworkSettings.Ports) == 0 {
log.Debugf("Filtering container without port %s", container.Name) log.Debugf("Filtering container without port %s", container.Name)
return false return false
@ -156,14 +203,14 @@ func containerFilter(container docker.Container) bool {
return true return true
} }
func (provider *Docker) getFrontendName(container docker.Container) string { func (provider *Docker) getFrontendName(container dockertypes.ContainerJSON) string {
// Replace '.' with '-' in quoted keys because of this issue https://github.com/BurntSushi/toml/issues/78 // Replace '.' with '-' in quoted keys because of this issue https://github.com/BurntSushi/toml/issues/78
return normalize(provider.getFrontendRule(container)) return normalize(provider.getFrontendRule(container))
} }
// GetFrontendRule returns the frontend rule for the specified container, using // GetFrontendRule returns the frontend rule for the specified container, using
// it's label. It returns a default one (Host) if the label is not present. // it's label. It returns a default one (Host) if the label is not present.
func (provider *Docker) getFrontendRule(container docker.Container) string { func (provider *Docker) getFrontendRule(container dockertypes.ContainerJSON) string {
// ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠ // ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
// TODO: backwards compatibility with DEPRECATED rule.Value // TODO: backwards compatibility with DEPRECATED rule.Value
if value, ok := container.Config.Labels["traefik.frontend.value"]; ok { if value, ok := container.Config.Labels["traefik.frontend.value"]; ok {
@ -179,14 +226,14 @@ func (provider *Docker) getFrontendRule(container docker.Container) string {
return "Host:" + getEscapedName(container.Name) + "." + provider.Domain return "Host:" + getEscapedName(container.Name) + "." + provider.Domain
} }
func (provider *Docker) getBackend(container docker.Container) string { func (provider *Docker) getBackend(container dockertypes.ContainerJSON) string {
if label, err := getLabel(container, "traefik.backend"); err == nil { if label, err := getLabel(container, "traefik.backend"); err == nil {
return label return label
} }
return normalize(container.Name) return normalize(container.Name)
} }
func (provider *Docker) getPort(container docker.Container) string { func (provider *Docker) getPort(container dockertypes.ContainerJSON) string {
if label, err := getLabel(container, "traefik.port"); err == nil { if label, err := getLabel(container, "traefik.port"); err == nil {
return label return label
} }
@ -196,42 +243,42 @@ func (provider *Docker) getPort(container docker.Container) string {
return "" return ""
} }
func (provider *Docker) getWeight(container docker.Container) string { func (provider *Docker) getWeight(container dockertypes.ContainerJSON) string {
if label, err := getLabel(container, "traefik.weight"); err == nil { if label, err := getLabel(container, "traefik.weight"); err == nil {
return label return label
} }
return "1" return "1"
} }
func (provider *Docker) getDomain(container docker.Container) string { func (provider *Docker) getDomain(container dockertypes.ContainerJSON) string {
if label, err := getLabel(container, "traefik.domain"); err == nil { if label, err := getLabel(container, "traefik.domain"); err == nil {
return label return label
} }
return provider.Domain return provider.Domain
} }
func (provider *Docker) getProtocol(container docker.Container) string { func (provider *Docker) getProtocol(container dockertypes.ContainerJSON) string {
if label, err := getLabel(container, "traefik.protocol"); err == nil { if label, err := getLabel(container, "traefik.protocol"); err == nil {
return label return label
} }
return "http" return "http"
} }
func (provider *Docker) getPassHostHeader(container docker.Container) string { func (provider *Docker) getPassHostHeader(container dockertypes.ContainerJSON) string {
if passHostHeader, err := getLabel(container, "traefik.frontend.passHostHeader"); err == nil { if passHostHeader, err := getLabel(container, "traefik.frontend.passHostHeader"); err == nil {
return passHostHeader return passHostHeader
} }
return "false" return "false"
} }
func (provider *Docker) getEntryPoints(container docker.Container) []string { func (provider *Docker) getEntryPoints(container dockertypes.ContainerJSON) []string {
if entryPoints, err := getLabel(container, "traefik.frontend.entryPoints"); err == nil { if entryPoints, err := getLabel(container, "traefik.frontend.entryPoints"); err == nil {
return strings.Split(entryPoints, ",") return strings.Split(entryPoints, ",")
} }
return []string{} return []string{}
} }
func getLabel(container docker.Container, label string) (string, error) { func getLabel(container dockertypes.ContainerJSON, label string) (string, error) {
for key, value := range container.Config.Labels { for key, value := range container.Config.Labels {
if key == label { if key == label {
return value, nil return value, nil
@ -240,7 +287,7 @@ func getLabel(container docker.Container, label string) (string, error) {
return "", errors.New("Label not found:" + label) return "", errors.New("Label not found:" + label)
} }
func getLabels(container docker.Container, labels []string) (map[string]string, error) { func getLabels(container dockertypes.ContainerJSON, labels []string) (map[string]string, error) {
var globalErr error var globalErr error
foundLabels := map[string]string{} foundLabels := map[string]string{}
for _, label := range labels { for _, label := range labels {
@ -256,14 +303,20 @@ func getLabels(container docker.Container, labels []string) (map[string]string,
return foundLabels, globalErr return foundLabels, globalErr
} }
func listContainers(dockerClient *docker.Client) []docker.Container { func listContainers(dockerClient client.APIClient) ([]dockertypes.ContainerJSON, error) {
containerList, _ := dockerClient.ListContainers(docker.ListContainersOptions{}) containerList, err := dockerClient.ContainerList(context.Background(), dockertypes.ContainerListOptions{})
containersInspected := []docker.Container{} if err != nil {
return []dockertypes.ContainerJSON{}, err
}
containersInspected := []dockertypes.ContainerJSON{}
// get inspect containers // get inspect containers
for _, container := range containerList { for _, container := range containerList {
containerInspected, _ := dockerClient.InspectContainer(container.ID) containerInspected, err := dockerClient.ContainerInspect(context.Background(), container.ID)
containersInspected = append(containersInspected, *containerInspected) if err != nil {
log.Warnf("Failed to inpsect container %s, error: %s", container.ID, err)
}
containersInspected = append(containersInspected, containerInspected)
} }
return containersInspected return containersInspected, nil
} }

View file

@ -6,7 +6,10 @@ import (
"testing" "testing"
"github.com/containous/traefik/types" "github.com/containous/traefik/types"
"github.com/fsouza/go-dockerclient" docker "github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/container"
"github.com/docker/engine-api/types/network"
"github.com/docker/go-connections/nat"
) )
func TestDockerGetFrontendName(t *testing.T) { func TestDockerGetFrontendName(t *testing.T) {
@ -15,20 +18,24 @@ func TestDockerGetFrontendName(t *testing.T) {
} }
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expected string expected string
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "foo", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "foo",
},
Config: &container.Config{},
}, },
expected: "Host-foo-docker-localhost", expected: "Host-foo-docker-localhost",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "bar", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "bar",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.frontend.rule": "Headers:User-Agent,bat/0.1.0", "traefik.frontend.rule": "Headers:User-Agent,bat/0.1.0",
}, },
@ -37,9 +44,11 @@ func TestDockerGetFrontendName(t *testing.T) {
expected: "Headers-User-Agent-bat-0-1-0", expected: "Headers-User-Agent-bat-0-1-0",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.frontend.rule": "Host:foo.bar", "traefik.frontend.rule": "Host:foo.bar",
}, },
@ -48,9 +57,11 @@ func TestDockerGetFrontendName(t *testing.T) {
expected: "Host-foo-bar", expected: "Host-foo-bar",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.frontend.rule": "Path:/test", "traefik.frontend.rule": "Path:/test",
}, },
@ -59,9 +70,11 @@ func TestDockerGetFrontendName(t *testing.T) {
expected: "Path-test", expected: "Path-test",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.frontend.rule": "PathPrefix:/test2", "traefik.frontend.rule": "PathPrefix:/test2",
}, },
@ -85,27 +98,33 @@ func TestDockerGetFrontendRule(t *testing.T) {
} }
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expected string expected string
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "foo", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "foo",
},
Config: &container.Config{},
}, },
expected: "Host:foo.docker.localhost", expected: "Host:foo.docker.localhost",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "bar", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "bar",
},
Config: &container.Config{},
}, },
expected: "Host:bar.docker.localhost", expected: "Host:bar.docker.localhost",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.frontend.rule": "Host:foo.bar", "traefik.frontend.rule": "Host:foo.bar",
}, },
@ -114,9 +133,11 @@ func TestDockerGetFrontendRule(t *testing.T) {
expected: "Host:foo.bar", expected: "Host:foo.bar",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.frontend.rule": "Path:/test", "traefik.frontend.rule": "Path:/test",
}, },
@ -138,27 +159,33 @@ func TestDockerGetBackend(t *testing.T) {
provider := &Docker{} provider := &Docker{}
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expected string expected string
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "foo", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "foo",
},
Config: &container.Config{},
}, },
expected: "foo", expected: "foo",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "bar", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "bar",
},
Config: &container.Config{},
}, },
expected: "bar", expected: "bar",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.backend": "foobar", "traefik.backend": "foobar",
}, },
@ -180,24 +207,30 @@ func TestDockerGetPort(t *testing.T) {
provider := &Docker{} provider := &Docker{}
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expected string expected string
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "foo", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "foo",
},
Config: &container.Config{},
NetworkSettings: &docker.NetworkSettings{}, NetworkSettings: &docker.NetworkSettings{},
}, },
expected: "", expected: "",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "bar", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "bar",
},
Config: &container.Config{},
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
}, },
}, },
@ -205,9 +238,9 @@ func TestDockerGetPort(t *testing.T) {
}, },
// FIXME handle this better.. // FIXME handle this better..
// { // {
// container: docker.Container{ // container: docker.ContainerJSON{
// Name: "bar", // Name: "bar",
// Config: &docker.Config{}, // Config: &container.Config{},
// NetworkSettings: &docker.NetworkSettings{ // NetworkSettings: &docker.NetworkSettings{
// Ports: map[docker.Port][]docker.PortBinding{ // Ports: map[docker.Port][]docker.PortBinding{
// "80/tcp": []docker.PortBinding{}, // "80/tcp": []docker.PortBinding{},
@ -218,16 +251,20 @@ func TestDockerGetPort(t *testing.T) {
// expected: "80", // expected: "80",
// }, // },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.port": "8080", "traefik.port": "8080",
}, },
}, },
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
}, },
}, },
@ -247,20 +284,24 @@ func TestDockerGetWeight(t *testing.T) {
provider := &Docker{} provider := &Docker{}
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expected string expected string
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "foo", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "foo",
},
Config: &container.Config{},
}, },
expected: "1", expected: "1",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.weight": "10", "traefik.weight": "10",
}, },
@ -284,20 +325,24 @@ func TestDockerGetDomain(t *testing.T) {
} }
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expected string expected string
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "foo", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "foo",
},
Config: &container.Config{},
}, },
expected: "docker.localhost", expected: "docker.localhost",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.domain": "foo.bar", "traefik.domain": "foo.bar",
}, },
@ -319,20 +364,24 @@ func TestDockerGetProtocol(t *testing.T) {
provider := &Docker{} provider := &Docker{}
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expected string expected string
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "foo", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "foo",
},
Config: &container.Config{},
}, },
expected: "http", expected: "http",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.protocol": "https", "traefik.protocol": "https",
}, },
@ -354,20 +403,24 @@ func TestDockerGetPassHostHeader(t *testing.T) {
provider := &Docker{} provider := &Docker{}
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expected string expected string
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "foo", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "foo",
},
Config: &container.Config{},
}, },
expected: "false", expected: "false",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.frontend.passHostHeader": "true", "traefik.frontend.passHostHeader": "true",
}, },
@ -387,18 +440,18 @@ func TestDockerGetPassHostHeader(t *testing.T) {
func TestDockerGetLabel(t *testing.T) { func TestDockerGetLabel(t *testing.T) {
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expected string expected string
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{}, Config: &container.Config{},
}, },
expected: "Label not found:", expected: "Label not found:",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{ Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"foo": "bar", "foo": "bar",
}, },
@ -424,20 +477,20 @@ func TestDockerGetLabel(t *testing.T) {
func TestDockerGetLabels(t *testing.T) { func TestDockerGetLabels(t *testing.T) {
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expectedLabels map[string]string expectedLabels map[string]string
expectedError string expectedError string
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{}, Config: &container.Config{},
}, },
expectedLabels: map[string]string{}, expectedLabels: map[string]string{},
expectedError: "Label not found:", expectedError: "Label not found:",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{ Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"foo": "fooz", "foo": "fooz",
}, },
@ -449,8 +502,8 @@ func TestDockerGetLabels(t *testing.T) {
expectedError: "Label not found: bar", expectedError: "Label not found: bar",
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{ Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"foo": "fooz", "foo": "fooz",
"bar": "barz", "bar": "barz",
@ -480,125 +533,168 @@ func TestDockerGetLabels(t *testing.T) {
func TestDockerTraefikFilter(t *testing.T) { func TestDockerTraefikFilter(t *testing.T) {
containers := []struct { containers := []struct {
container docker.Container container docker.ContainerJSON
expected bool expected bool
}{ }{
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{}, ContainerJSONBase: &docker.ContainerJSONBase{
Name: "container",
},
Config: &container.Config{},
NetworkSettings: &docker.NetworkSettings{}, NetworkSettings: &docker.NetworkSettings{},
}, },
expected: false, expected: false,
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{ ContainerJSONBase: &docker.ContainerJSONBase{
Name: "container",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.enable": "false", "traefik.enable": "false",
}, },
}, },
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
}, },
}, },
expected: false, expected: false,
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{ ContainerJSONBase: &docker.ContainerJSONBase{
Name: "container",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.frontend.rule": "Host:foo.bar", "traefik.frontend.rule": "Host:foo.bar",
}, },
}, },
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
}, },
}, },
expected: true, expected: true,
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{}, ContainerJSONBase: &docker.ContainerJSONBase{
Name: "container",
},
Config: &container.Config{},
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"443/tcp": {}, "80/tcp": {},
"443/tcp": {},
},
}, },
}, },
}, },
expected: false, expected: false,
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{}, ContainerJSONBase: &docker.ContainerJSONBase{
Name: "container",
},
Config: &container.Config{},
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
}, },
}, },
expected: true, expected: true,
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{ ContainerJSONBase: &docker.ContainerJSONBase{
Name: "container",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.port": "80", "traefik.port": "80",
}, },
}, },
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"443/tcp": {}, "80/tcp": {},
"443/tcp": {},
},
}, },
}, },
}, },
expected: true, expected: true,
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{ ContainerJSONBase: &docker.ContainerJSONBase{
Name: "container",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.enable": "true", "traefik.enable": "true",
}, },
}, },
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
}, },
}, },
expected: true, expected: true,
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{ ContainerJSONBase: &docker.ContainerJSONBase{
Name: "container",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.enable": "anything", "traefik.enable": "anything",
}, },
}, },
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
}, },
}, },
expected: true, expected: true,
}, },
{ {
container: docker.Container{ container: docker.ContainerJSON{
Config: &docker.Config{ ContainerJSONBase: &docker.ContainerJSONBase{
Name: "container",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.frontend.rule": "Host:foo.bar", "traefik.frontend.rule": "Host:foo.bar",
}, },
}, },
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
}, },
}, },
@ -616,26 +712,30 @@ func TestDockerTraefikFilter(t *testing.T) {
func TestDockerLoadDockerConfig(t *testing.T) { func TestDockerLoadDockerConfig(t *testing.T) {
cases := []struct { cases := []struct {
containers []docker.Container containers []docker.ContainerJSON
expectedFrontends map[string]*types.Frontend expectedFrontends map[string]*types.Frontend
expectedBackends map[string]*types.Backend expectedBackends map[string]*types.Backend
}{ }{
{ {
containers: []docker.Container{}, containers: []docker.ContainerJSON{},
expectedFrontends: map[string]*types.Frontend{}, expectedFrontends: map[string]*types.Frontend{},
expectedBackends: map[string]*types.Backend{}, expectedBackends: map[string]*types.Backend{},
}, },
{ {
containers: []docker.Container{ containers: []docker.ContainerJSON{
{ {
Name: "test", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{}, Name: "test",
},
Config: &container.Config{},
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
Networks: map[string]docker.ContainerNetwork{ Networks: map[string]*network.EndpointSettings{
"bridgde": { "bridge": {
IPAddress: "127.0.0.1", IPAddress: "127.0.0.1",
}, },
}, },
@ -667,38 +767,46 @@ func TestDockerLoadDockerConfig(t *testing.T) {
}, },
}, },
{ {
containers: []docker.Container{ containers: []docker.ContainerJSON{
{ {
Name: "test1", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test1",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.backend": "foobar", "traefik.backend": "foobar",
"traefik.frontend.entryPoints": "http,https", "traefik.frontend.entryPoints": "http,https",
}, },
}, },
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
Networks: map[string]docker.ContainerNetwork{ Networks: map[string]*network.EndpointSettings{
"bridgde": { "bridge": {
IPAddress: "127.0.0.1", IPAddress: "127.0.0.1",
}, },
}, },
}, },
}, },
{ {
Name: "test2", ContainerJSONBase: &docker.ContainerJSONBase{
Config: &docker.Config{ Name: "test2",
},
Config: &container.Config{
Labels: map[string]string{ Labels: map[string]string{
"traefik.backend": "foobar", "traefik.backend": "foobar",
}, },
}, },
NetworkSettings: &docker.NetworkSettings{ NetworkSettings: &docker.NetworkSettings{
Ports: map[docker.Port][]docker.PortBinding{ NetworkSettingsBase: docker.NetworkSettingsBase{
"80/tcp": {}, Ports: nat.PortMap{
"80/tcp": {},
},
}, },
Networks: map[string]docker.ContainerNetwork{ Networks: map[string]*network.EndpointSettings{
"bridge": { "bridge": {
IPAddress: "127.0.0.1", IPAddress: "127.0.0.1",
}, },