Merge v1.1.1 into master
Signed-off-by: Emile Vauge <emile@vauge.com>
This commit is contained in:
commit
dca08af003
41 changed files with 760 additions and 170 deletions
|
@ -17,7 +17,7 @@ type BoltDb struct {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *BoltDb) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
|
||||
func (provider *BoltDb) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
store, err := provider.CreateStore()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to Connect to KV store: %v", err)
|
||||
|
|
|
@ -17,7 +17,7 @@ type Consul struct {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *Consul) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
|
||||
func (provider *Consul) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
store, err := provider.CreateStore()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to Connect to KV store: %v", err)
|
||||
|
|
|
@ -317,7 +317,7 @@ func (provider *ConsulCatalog) watch(configurationChan chan<- types.ConfigMessag
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *ConsulCatalog) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
|
||||
func (provider *ConsulCatalog) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
config := api.DefaultConfig()
|
||||
config.Address = provider.Endpoint
|
||||
client, err := api.NewClient(config)
|
||||
|
|
|
@ -61,7 +61,7 @@ func TestConsulCatalogGetAttribute(t *testing.T) {
|
|||
"traefik.backend.weight=42",
|
||||
},
|
||||
key: "backend.weight",
|
||||
defaultValue: "",
|
||||
defaultValue: "0",
|
||||
expected: "42",
|
||||
},
|
||||
{
|
||||
|
@ -70,8 +70,8 @@ func TestConsulCatalogGetAttribute(t *testing.T) {
|
|||
"traefik.backend.wei=42",
|
||||
},
|
||||
key: "backend.weight",
|
||||
defaultValue: "",
|
||||
expected: "",
|
||||
defaultValue: "0",
|
||||
expected: "0",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ func (provider *Docker) createClient() (client.APIClient, error) {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *Docker) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
|
||||
func (provider *Docker) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
provider.Constraints = append(provider.Constraints, constraints...)
|
||||
// TODO register this routine in pool, and watch for stop channel
|
||||
safe.Go(func() {
|
||||
|
@ -363,10 +363,6 @@ func (provider *Docker) containerFilter(container dockerData) bool {
|
|||
log.Debugf("Filtering container without port and no traefik.port label %s", container.Name)
|
||||
return false
|
||||
}
|
||||
if len(container.NetworkSettings.Ports) > 1 && err != nil {
|
||||
log.Debugf("Filtering container with more than 1 port and no traefik.port label %s", container.Name)
|
||||
return false
|
||||
}
|
||||
|
||||
if !isContainerEnabled(container, provider.ExposedByDefault) {
|
||||
log.Debugf("Filtering disabled container %s", container.Name)
|
||||
|
@ -405,7 +401,7 @@ func (provider *Docker) getFrontendRule(container dockerData) string {
|
|||
|
||||
func (provider *Docker) getBackend(container dockerData) string {
|
||||
if label, err := getLabel(container, "traefik.backend"); err == nil {
|
||||
return label
|
||||
return normalize(label)
|
||||
}
|
||||
return normalize(container.Name)
|
||||
}
|
||||
|
@ -458,7 +454,7 @@ func (provider *Docker) getWeight(container dockerData) string {
|
|||
if label, err := getLabel(container, "traefik.weight"); err == nil {
|
||||
return label
|
||||
}
|
||||
return "1"
|
||||
return "0"
|
||||
}
|
||||
|
||||
func (provider *Docker) getSticky(container dockerData) string {
|
||||
|
@ -563,6 +559,10 @@ func parseContainer(container dockertypes.ContainerJSON) dockerData {
|
|||
if container.ContainerJSONBase.HostConfig != nil {
|
||||
dockerData.NetworkSettings.NetworkMode = container.ContainerJSONBase.HostConfig.NetworkMode
|
||||
}
|
||||
|
||||
if container.State != nil && container.State.Health != nil {
|
||||
dockerData.Health = container.State.Health.Status
|
||||
}
|
||||
}
|
||||
|
||||
if container.Config != nil && container.Config.Labels != nil {
|
||||
|
@ -586,10 +586,6 @@ func parseContainer(container dockertypes.ContainerJSON) dockerData {
|
|||
|
||||
}
|
||||
|
||||
if container.State != nil && container.State.Health != nil {
|
||||
dockerData.Health = container.State.Health.Status
|
||||
}
|
||||
|
||||
return dockerData
|
||||
}
|
||||
|
||||
|
|
|
@ -390,6 +390,27 @@ func TestDockerGetPort(t *testing.T) {
|
|||
},
|
||||
expected: "8080",
|
||||
},
|
||||
{
|
||||
container: docker.ContainerJSON{
|
||||
ContainerJSONBase: &docker.ContainerJSONBase{
|
||||
Name: "test-multi-ports",
|
||||
},
|
||||
Config: &container.Config{
|
||||
Labels: map[string]string{
|
||||
"traefik.port": "8080",
|
||||
},
|
||||
},
|
||||
NetworkSettings: &docker.NetworkSettings{
|
||||
NetworkSettingsBase: docker.NetworkSettingsBase{
|
||||
Ports: nat.PortMap{
|
||||
"8080/tcp": {},
|
||||
"80/tcp": {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "8080",
|
||||
},
|
||||
}
|
||||
|
||||
for _, e := range containers {
|
||||
|
@ -415,7 +436,7 @@ func TestDockerGetWeight(t *testing.T) {
|
|||
},
|
||||
Config: &container.Config{},
|
||||
},
|
||||
expected: "1",
|
||||
expected: "0",
|
||||
},
|
||||
{
|
||||
container: docker.ContainerJSON{
|
||||
|
@ -735,7 +756,7 @@ func TestDockerTraefikFilter(t *testing.T) {
|
|||
{
|
||||
container: docker.ContainerJSON{
|
||||
ContainerJSONBase: &docker.ContainerJSONBase{
|
||||
Name: "container",
|
||||
Name: "container-multi-ports",
|
||||
},
|
||||
Config: &container.Config{},
|
||||
NetworkSettings: &docker.NetworkSettings{
|
||||
|
@ -748,7 +769,7 @@ func TestDockerTraefikFilter(t *testing.T) {
|
|||
},
|
||||
},
|
||||
exposedByDefault: true,
|
||||
expected: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
container: docker.ContainerJSON{
|
||||
|
@ -951,7 +972,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
|||
Servers: map[string]types.Server{
|
||||
"server-test": {
|
||||
URL: "http://127.0.0.1:80",
|
||||
Weight: 1,
|
||||
Weight: 0,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
|
@ -1033,11 +1054,11 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
|||
Servers: map[string]types.Server{
|
||||
"server-test1": {
|
||||
URL: "http://127.0.0.1:80",
|
||||
Weight: 1,
|
||||
Weight: 0,
|
||||
},
|
||||
"server-test2": {
|
||||
URL: "http://127.0.0.1:80",
|
||||
Weight: 1,
|
||||
Weight: 0,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
|
@ -1091,7 +1112,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
|||
Servers: map[string]types.Server{
|
||||
"server-test1": {
|
||||
URL: "http://127.0.0.1:80",
|
||||
Weight: 1,
|
||||
Weight: 0,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: &types.CircuitBreaker{
|
||||
|
@ -1506,7 +1527,7 @@ func TestSwarmGetWeight(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expected: "1",
|
||||
expected: "0",
|
||||
networks: map[string]*docker.NetworkResource{},
|
||||
},
|
||||
{
|
||||
|
@ -2034,7 +2055,7 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
|||
Servers: map[string]types.Server{
|
||||
"server-test": {
|
||||
URL: "http://127.0.0.1:80",
|
||||
Weight: 1,
|
||||
Weight: 0,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
|
@ -2122,11 +2143,11 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
|||
Servers: map[string]types.Server{
|
||||
"server-test1": {
|
||||
URL: "http://127.0.0.1:80",
|
||||
Weight: 1,
|
||||
Weight: 0,
|
||||
},
|
||||
"server-test2": {
|
||||
URL: "http://127.0.0.1:80",
|
||||
Weight: 1,
|
||||
Weight: 0,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
|
|
|
@ -17,7 +17,7 @@ type Etcd struct {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *Etcd) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
|
||||
func (provider *Etcd) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
store, err := provider.CreateStore()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to Connect to KV store: %v", err)
|
||||
|
|
|
@ -23,7 +23,7 @@ type Eureka struct {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *Eureka) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, _ []types.Constraint) error {
|
||||
func (provider *Eureka) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, _ types.Constraints) error {
|
||||
|
||||
operation := func() error {
|
||||
configuration, err := provider.buildConfiguration()
|
||||
|
|
|
@ -21,7 +21,7 @@ type File struct {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *File) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, _ []types.Constraint) error {
|
||||
func (provider *File) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Error("Error creating file watcher", err)
|
||||
|
|
|
@ -42,7 +42,7 @@ func (provider *Kubernetes) newK8sClient() (k8s.Client, error) {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
|
||||
func (provider *Kubernetes) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
k8sClient, err := provider.newK8sClient()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -83,7 +83,7 @@ func (provider *Kv) watchKv(configurationChan chan<- types.ConfigMessage, prefix
|
|||
return nil
|
||||
}
|
||||
|
||||
func (provider *Kv) provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
|
||||
func (provider *Kv) provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
provider.Constraints = append(provider.Constraints, constraints...)
|
||||
operation := func() error {
|
||||
if _, err := provider.kvclient.Exists("qmslkjdfmqlskdjfmqlksjazçueznbvbwzlkajzebvkwjdcqmlsfj"); err != nil {
|
||||
|
|
|
@ -408,7 +408,7 @@ func TestKVLoadConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Key: "traefik/backends/backend.with.dot.too/servers/server.with.dot/weight",
|
||||
Value: []byte("1"),
|
||||
Value: []byte("0"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -420,7 +420,7 @@ func TestKVLoadConfig(t *testing.T) {
|
|||
Servers: map[string]types.Server{
|
||||
"server.with.dot": {
|
||||
URL: "http://172.17.0.2:80",
|
||||
Weight: 1,
|
||||
Weight: 0,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
@ -53,7 +52,7 @@ type lightMarathonClient interface {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
|
||||
func (provider *Marathon) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
provider.Constraints = append(provider.Constraints, constraints...)
|
||||
operation := func() error {
|
||||
config := marathon.NewDefaultConfig()
|
||||
|
@ -226,10 +225,7 @@ func (provider *Marathon) taskFilter(task marathon.Task, applications *marathon.
|
|||
log.Debugf("Filtering marathon task %s specifying both traefik.portIndex and traefik.port labels", task.AppID)
|
||||
return false
|
||||
}
|
||||
if portIndexLabel == "" && portValueLabel == "" && len(application.Ports) > 1 {
|
||||
log.Debugf("Filtering marathon task %s with more than 1 port and no traefik.portIndex or traefik.port label", task.AppID)
|
||||
return false
|
||||
}
|
||||
|
||||
if portIndexLabel != "" {
|
||||
index, err := strconv.Atoi((*application.Labels)["traefik.portIndex"])
|
||||
if err != nil || index < 0 || index > len(application.Ports)-1 {
|
||||
|
@ -429,7 +425,7 @@ func (provider *Marathon) getFrontendBackend(application marathon.Application) s
|
|||
func (provider *Marathon) getSubDomain(name string) string {
|
||||
if provider.GroupsAsSubDomains {
|
||||
splitedName := strings.Split(strings.TrimPrefix(name, "/"), "/")
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(splitedName)))
|
||||
reverseStringSlice(&splitedName)
|
||||
reverseName := strings.Join(splitedName, ".")
|
||||
return reverseName
|
||||
}
|
||||
|
|
|
@ -371,30 +371,30 @@ func TestMarathonTaskFilter(t *testing.T) {
|
|||
},
|
||||
{
|
||||
task: marathon.Task{
|
||||
AppID: "foo",
|
||||
Ports: []int{80},
|
||||
AppID: "multiple-ports",
|
||||
Ports: []int{80, 443},
|
||||
},
|
||||
applications: &marathon.Applications{
|
||||
Apps: []marathon.Application{
|
||||
{
|
||||
ID: "foo",
|
||||
ID: "multiple-ports",
|
||||
Ports: []int{80, 443},
|
||||
Labels: &map[string]string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
expected: true,
|
||||
exposedByDefault: true,
|
||||
},
|
||||
{
|
||||
task: marathon.Task{
|
||||
AppID: "foo",
|
||||
AppID: "disable",
|
||||
Ports: []int{80},
|
||||
},
|
||||
applications: &marathon.Applications{
|
||||
Apps: []marathon.Application{
|
||||
{
|
||||
ID: "foo",
|
||||
ID: "disable",
|
||||
Ports: []int{80},
|
||||
Labels: &map[string]string{
|
||||
"traefik.enable": "false",
|
||||
|
@ -523,7 +523,7 @@ func TestMarathonTaskFilter(t *testing.T) {
|
|||
},
|
||||
{
|
||||
task: marathon.Task{
|
||||
AppID: "foo",
|
||||
AppID: "healthcheck-false",
|
||||
Ports: []int{80},
|
||||
HealthCheckResults: []*marathon.HealthCheckResult{
|
||||
{
|
||||
|
@ -534,7 +534,7 @@ func TestMarathonTaskFilter(t *testing.T) {
|
|||
applications: &marathon.Applications{
|
||||
Apps: []marathon.Application{
|
||||
{
|
||||
ID: "foo",
|
||||
ID: "healthcheck-false",
|
||||
Ports: []int{80},
|
||||
Labels: &map[string]string{},
|
||||
HealthChecks: &[]marathon.HealthCheck{
|
||||
|
@ -576,13 +576,13 @@ func TestMarathonTaskFilter(t *testing.T) {
|
|||
},
|
||||
{
|
||||
task: marathon.Task{
|
||||
AppID: "foo",
|
||||
AppID: "single-port",
|
||||
Ports: []int{80},
|
||||
},
|
||||
applications: &marathon.Applications{
|
||||
Apps: []marathon.Application{
|
||||
{
|
||||
ID: "foo",
|
||||
ID: "single-port",
|
||||
Ports: []int{80},
|
||||
Labels: &map[string]string{},
|
||||
},
|
||||
|
@ -593,7 +593,7 @@ func TestMarathonTaskFilter(t *testing.T) {
|
|||
},
|
||||
{
|
||||
task: marathon.Task{
|
||||
AppID: "foo",
|
||||
AppID: "healthcheck-alive",
|
||||
Ports: []int{80},
|
||||
HealthCheckResults: []*marathon.HealthCheckResult{
|
||||
{
|
||||
|
@ -604,7 +604,7 @@ func TestMarathonTaskFilter(t *testing.T) {
|
|||
applications: &marathon.Applications{
|
||||
Apps: []marathon.Application{
|
||||
{
|
||||
ID: "foo",
|
||||
ID: "healthcheck-alive",
|
||||
Ports: []int{80},
|
||||
Labels: &map[string]string{},
|
||||
HealthChecks: &[]marathon.HealthCheck{
|
||||
|
@ -677,7 +677,7 @@ func TestMarathonTaskFilter(t *testing.T) {
|
|||
for _, c := range cases {
|
||||
actual := provider.taskFilter(c.task, c.applications, c.exposedByDefault)
|
||||
if actual != c.expected {
|
||||
t.Fatalf("expected %v, got %v", c.expected, actual)
|
||||
t.Fatalf("App %s: expected %v, got %v", c.task.AppID, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -740,7 +740,7 @@ func TestMarathonAppConstraints(t *testing.T) {
|
|||
MarathonLBCompatibility: c.marathonLBCompatibility,
|
||||
}
|
||||
constraint, _ := types.NewConstraint("tag==valid")
|
||||
provider.Constraints = []types.Constraint{*constraint}
|
||||
provider.Constraints = types.Constraints{constraint}
|
||||
actual := provider.applicationFilter(c.application, c.filteredTasks)
|
||||
if actual != c.expected {
|
||||
t.Fatalf("expected %v, got %v: %v", c.expected, actual, c.application)
|
||||
|
@ -820,7 +820,7 @@ func TestMarathonTaskConstraints(t *testing.T) {
|
|||
MarathonLBCompatibility: c.marathonLBCompatibility,
|
||||
}
|
||||
constraint, _ := types.NewConstraint("tag==valid")
|
||||
provider.Constraints = []types.Constraint{*constraint}
|
||||
provider.Constraints = types.Constraints{constraint}
|
||||
apps := new(marathon.Applications)
|
||||
apps.Apps = c.applications
|
||||
actual := provider.taskFilter(c.filteredTask, apps, true)
|
||||
|
@ -927,12 +927,12 @@ func TestMarathonGetPort(t *testing.T) {
|
|||
{
|
||||
applications: []marathon.Application{
|
||||
{
|
||||
ID: "test1",
|
||||
ID: "multiple-ports-take-first",
|
||||
Labels: &map[string]string{},
|
||||
},
|
||||
},
|
||||
task: marathon.Task{
|
||||
AppID: "test1",
|
||||
AppID: "multiple-ports-take-first",
|
||||
Ports: []int{80, 443},
|
||||
},
|
||||
expected: "80",
|
||||
|
@ -1280,3 +1280,33 @@ func TestMarathonGetBackend(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarathonGetSubDomain(t *testing.T) {
|
||||
providerGroups := &Marathon{GroupsAsSubDomains: true}
|
||||
providerNoGroups := &Marathon{GroupsAsSubDomains: false}
|
||||
|
||||
apps := []struct {
|
||||
path string
|
||||
expected string
|
||||
provider *Marathon
|
||||
}{
|
||||
{"/test", "test", providerNoGroups},
|
||||
{"/test", "test", providerGroups},
|
||||
{"/a/b/c/d", "d.c.b.a", providerGroups},
|
||||
{"/b/a/d/c", "c.d.a.b", providerGroups},
|
||||
{"/d/c/b/a", "a.b.c.d", providerGroups},
|
||||
{"/c/d/a/b", "b.a.d.c", providerGroups},
|
||||
{"/a/b/c/d", "a-b-c-d", providerNoGroups},
|
||||
{"/b/a/d/c", "b-a-d-c", providerNoGroups},
|
||||
{"/d/c/b/a", "d-c-b-a", providerNoGroups},
|
||||
{"/c/d/a/b", "c-d-a-b", providerNoGroups},
|
||||
}
|
||||
|
||||
for _, a := range apps {
|
||||
actual := a.provider.getSubDomain(a.path)
|
||||
|
||||
if actual != a.expected {
|
||||
t.Errorf("expected %q, got %q", a.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"text/template"
|
||||
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/ty/fun"
|
||||
"github.com/cenk/backoff"
|
||||
"github.com/containous/traefik/job"
|
||||
|
@ -20,8 +22,6 @@ import (
|
|||
"github.com/mesosphere/mesos-dns/records"
|
||||
"github.com/mesosphere/mesos-dns/records/state"
|
||||
"github.com/mesosphere/mesos-dns/util"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ Provider = (*Mesos)(nil)
|
||||
|
@ -42,7 +42,7 @@ type Mesos struct {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *Mesos) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
|
||||
func (provider *Mesos) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
operation := func() error {
|
||||
|
||||
// initialize logging
|
||||
|
@ -212,10 +212,6 @@ func mesosTaskFilter(task state.Task, exposedByDefaultFlag bool) bool {
|
|||
log.Debugf("Filtering mesos task %s specifying both traefik.portIndex and traefik.port labels", task.Name)
|
||||
return false
|
||||
}
|
||||
if portIndexLabel == "" && portValueLabel == "" && len(task.DiscoveryInfo.Ports.DiscoveryPorts) > 1 {
|
||||
log.Debugf("Filtering mesos task %s with more than 1 port and no traefik.portIndex or traefik.port label", task.Name)
|
||||
return false
|
||||
}
|
||||
if portIndexLabel != "" {
|
||||
index, err := strconv.Atoi(labels(task, "traefik.portIndex"))
|
||||
if err != nil || index < 0 || index > len(task.DiscoveryInfo.Ports.DiscoveryPorts)-1 {
|
||||
|
@ -439,7 +435,7 @@ func Ignore(f ErrorFunction) {
|
|||
func (provider *Mesos) getSubDomain(name string) string {
|
||||
if provider.GroupsAsSubDomains {
|
||||
splitedName := strings.Split(strings.TrimPrefix(name, "/"), "/")
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(splitedName)))
|
||||
reverseStringSlice(&splitedName)
|
||||
reverseName := strings.Join(splitedName, ".")
|
||||
return reverseName
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/containous/traefik/log"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/mesosphere/mesos-dns/records/state"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMesosTaskFilter(t *testing.T) {
|
||||
|
@ -95,7 +96,7 @@ func TestMesosTaskFilter(t *testing.T) {
|
|||
setLabels("traefik.enable", "true"),
|
||||
discovery(setDiscoveryPorts("TCP", 80, "WEB HTTP", "TCP", 443, "WEB HTTPS")),
|
||||
),
|
||||
expected: false, // more than 1 discovery port but no traefik.port* label
|
||||
expected: true, // Default to first index
|
||||
exposedByDefault: true,
|
||||
},
|
||||
{
|
||||
|
@ -244,6 +245,36 @@ func TestMesosLoadConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMesosGetSubDomain(t *testing.T) {
|
||||
providerGroups := &Mesos{GroupsAsSubDomains: true}
|
||||
providerNoGroups := &Mesos{GroupsAsSubDomains: false}
|
||||
|
||||
apps := []struct {
|
||||
path string
|
||||
expected string
|
||||
provider *Mesos
|
||||
}{
|
||||
{"/test", "test", providerNoGroups},
|
||||
{"/test", "test", providerGroups},
|
||||
{"/a/b/c/d", "d.c.b.a", providerGroups},
|
||||
{"/b/a/d/c", "c.d.a.b", providerGroups},
|
||||
{"/d/c/b/a", "a.b.c.d", providerGroups},
|
||||
{"/c/d/a/b", "b.a.d.c", providerGroups},
|
||||
{"/a/b/c/d", "a-b-c-d", providerNoGroups},
|
||||
{"/b/a/d/c", "b-a-d-c", providerNoGroups},
|
||||
{"/d/c/b/a", "d-c-b-a", providerNoGroups},
|
||||
{"/c/d/a/b", "c-d-a-b", providerNoGroups},
|
||||
}
|
||||
|
||||
for _, a := range apps {
|
||||
actual := a.provider.getSubDomain(a.path)
|
||||
|
||||
if actual != a.expected {
|
||||
t.Errorf("expected %q, got %q", a.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test helpers
|
||||
|
||||
type (
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
type Provider interface {
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error
|
||||
Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error
|
||||
}
|
||||
|
||||
// BaseProvider should be inherited by providers
|
||||
|
@ -44,7 +44,7 @@ func (p *BaseProvider) MatchConstraints(tags []string) (bool, *types.Constraint)
|
|||
for _, constraint := range p.Constraints {
|
||||
// xor: if ok and constraint.MustMatch are equal, then no tag is currently matching with the constraint
|
||||
if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); ok != constraint.MustMatch {
|
||||
return false, &constraint
|
||||
return false, constraint
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,12 @@ func normalize(name string) string {
|
|||
return strings.Join(strings.FieldsFunc(name, fargs), "-")
|
||||
}
|
||||
|
||||
func reverseStringSlice(slice *[]string) {
|
||||
for i, j := 0, len(*slice)-1; i < j; i, j = i+1, j-1 {
|
||||
(*slice)[i], (*slice)[j] = (*slice)[j], (*slice)[i]
|
||||
}
|
||||
}
|
||||
|
||||
// ClientTLS holds TLS specific configurations as client
|
||||
// CA, Cert and Key can be either path or file contents
|
||||
type ClientTLS struct {
|
||||
|
|
|
@ -230,13 +230,13 @@ func TestNilClientTLS(t *testing.T) {
|
|||
|
||||
func TestMatchingConstraints(t *testing.T) {
|
||||
cases := []struct {
|
||||
constraints []types.Constraint
|
||||
constraints types.Constraints
|
||||
tags []string
|
||||
expected bool
|
||||
}{
|
||||
// simple test: must match
|
||||
{
|
||||
constraints: []types.Constraint{
|
||||
constraints: types.Constraints{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
|
@ -250,7 +250,7 @@ func TestMatchingConstraints(t *testing.T) {
|
|||
},
|
||||
// simple test: must match but does not match
|
||||
{
|
||||
constraints: []types.Constraint{
|
||||
constraints: types.Constraints{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
|
@ -264,7 +264,7 @@ func TestMatchingConstraints(t *testing.T) {
|
|||
},
|
||||
// simple test: must not match
|
||||
{
|
||||
constraints: []types.Constraint{
|
||||
constraints: types.Constraints{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: false,
|
||||
|
@ -278,7 +278,7 @@ func TestMatchingConstraints(t *testing.T) {
|
|||
},
|
||||
// complex test: globbing
|
||||
{
|
||||
constraints: []types.Constraint{
|
||||
constraints: types.Constraints{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
|
@ -292,7 +292,7 @@ func TestMatchingConstraints(t *testing.T) {
|
|||
},
|
||||
// complex test: multiple constraints
|
||||
{
|
||||
constraints: []types.Constraint{
|
||||
constraints: types.Constraints{
|
||||
{
|
||||
Key: "tag",
|
||||
MustMatch: true,
|
||||
|
|
|
@ -17,7 +17,7 @@ type Zookepper struct {
|
|||
|
||||
// Provide allows the provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (provider *Zookepper) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints []types.Constraint) error {
|
||||
func (provider *Zookepper) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||
store, err := provider.CreateStore()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to Connect to KV store: %v", err)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue