Marathon provider uses port or portIndex from label.
This commit is contained in:
parent
f10bbd8c69
commit
cfbd43d1ee
4 changed files with 212 additions and 15 deletions
|
@ -487,7 +487,8 @@ domain = "marathon.localhost"
|
||||||
Labels can be used on containers to override default behaviour:
|
Labels can be used on containers to override default behaviour:
|
||||||
|
|
||||||
- `traefik.backend=foo`: assign the application to `foo` backend
|
- `traefik.backend=foo`: assign the application to `foo` backend
|
||||||
- `traefik.port=80`: register this port. Useful when the application exposes multiples ports.
|
- `traefik.portIndex=1`: register port by index in the application's ports array. Useful when the application exposes multiple ports.
|
||||||
|
- `traefik.port=80`: register the explicit application port value. Cannot be used alongside `traefik.portIndex`.
|
||||||
- `traefik.protocol=https`: override the default `http` protocol
|
- `traefik.protocol=https`: override the default `http` protocol
|
||||||
- `traefik.weight=10`: assign this weight to the application
|
- `traefik.weight=10`: assign this weight to the application
|
||||||
- `traefik.enable=false`: disable this application in Træfɪk
|
- `traefik.enable=false`: disable this application in Træfɪk
|
||||||
|
|
|
@ -123,20 +123,55 @@ func taskFilter(task marathon.Task, applications *marathon.Applications) bool {
|
||||||
log.Debug("Filtering marathon task without port %s", task.AppID)
|
log.Debug("Filtering marathon task without port %s", task.AppID)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
application, errApp := getApplication(task, applications.Apps)
|
application, err := getApplication(task, applications.Apps)
|
||||||
if errApp != nil {
|
if err != nil {
|
||||||
log.Errorf("Unable to get marathon application from task %s", task.AppID)
|
log.Errorf("Unable to get marathon application from task %s", task.AppID)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
_, err := strconv.Atoi(application.Labels["traefik.port"])
|
|
||||||
if len(application.Ports) > 1 && err != nil {
|
|
||||||
log.Debugf("Filtering marathon task %s with more than 1 port and no traefik.port label", task.AppID)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if application.Labels["traefik.enable"] == "false" {
|
if application.Labels["traefik.enable"] == "false" {
|
||||||
log.Debugf("Filtering disabled marathon task %s", task.AppID)
|
log.Debugf("Filtering disabled marathon task %s", task.AppID)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//filter indeterminable task port
|
||||||
|
portIndexLabel := application.Labels["traefik.portIndex"]
|
||||||
|
portValueLabel := application.Labels["traefik.port"]
|
||||||
|
if portIndexLabel != "" && portValueLabel != "" {
|
||||||
|
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 {
|
||||||
|
log.Debugf("Filtering marathon task %s with unexpected value for traefik.portIndex label", task.AppID)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if portValueLabel != "" {
|
||||||
|
port, err := strconv.Atoi(application.Labels["traefik.port"])
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("Filtering marathon task %s with unexpected value for traefik.port label", task.AppID)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var foundPort bool
|
||||||
|
for _, exposedPort := range task.Ports {
|
||||||
|
if port == exposedPort {
|
||||||
|
foundPort = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !foundPort {
|
||||||
|
log.Debugf("Filtering marathon task %s without a matching port for traefik.port label", task.AppID)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//filter healthchecks
|
//filter healthchecks
|
||||||
if application.HasHealthChecks() {
|
if application.HasHealthChecks() {
|
||||||
if task.HasHealthCheckResults() {
|
if task.HasHealthCheckResults() {
|
||||||
|
@ -179,7 +214,22 @@ func (provider *Marathon) getLabel(application marathon.Application, label strin
|
||||||
return "", errors.New("Label not found:" + label)
|
return "", errors.New("Label not found:" + label)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Marathon) getPort(task marathon.Task) string {
|
func (provider *Marathon) getPort(task marathon.Task, applications []marathon.Application) string {
|
||||||
|
application, err := getApplication(task, applications)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Unable to get marathon application from task %s", task.AppID)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if portIndexLabel, err := provider.getLabel(application, "traefik.portIndex"); err == nil {
|
||||||
|
if index, err := strconv.Atoi(portIndexLabel); err == nil {
|
||||||
|
return strconv.Itoa(task.Ports[index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if portValueLabel, err := provider.getLabel(application, "traefik.port"); err == nil {
|
||||||
|
return portValueLabel
|
||||||
|
}
|
||||||
|
|
||||||
for _, port := range task.Ports {
|
for _, port := range task.Ports {
|
||||||
return strconv.Itoa(port)
|
return strconv.Itoa(port)
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,6 +201,97 @@ func TestMarathonTaskFilter(t *testing.T) {
|
||||||
},
|
},
|
||||||
expected: false,
|
expected: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "specify-port-number",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
},
|
||||||
|
applications: &marathon.Applications{
|
||||||
|
Apps: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "specify-port-number",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"traefik.port": "80",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "specify-unknown-port-number",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
},
|
||||||
|
applications: &marathon.Applications{
|
||||||
|
Apps: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "specify-unknown-port-number",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"traefik.port": "8080",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "specify-port-index",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
},
|
||||||
|
applications: &marathon.Applications{
|
||||||
|
Apps: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "specify-port-index",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"traefik.portIndex": "0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "specify-out-of-range-port-index",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
},
|
||||||
|
applications: &marathon.Applications{
|
||||||
|
Apps: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "specify-out-of-range-port-index",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"traefik.portIndex": "2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "specify-both-port-index-and-number",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
},
|
||||||
|
applications: &marathon.Applications{
|
||||||
|
Apps: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "specify-both-port-index-and-number",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"traefik.port": "443",
|
||||||
|
"traefik.portIndex": "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "foo",
|
AppID: "foo",
|
||||||
|
@ -370,29 +461,84 @@ func TestMarathonGetPort(t *testing.T) {
|
||||||
provider := &Marathon{}
|
provider := &Marathon{}
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
task marathon.Task
|
applications []marathon.Application
|
||||||
expected string
|
task marathon.Task
|
||||||
|
expected string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
task: marathon.Task{},
|
applications: []marathon.Application{},
|
||||||
|
task: marathon.Task{},
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "test1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "test2",
|
||||||
|
},
|
||||||
expected: "",
|
expected: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "test1",
|
||||||
|
},
|
||||||
|
},
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
|
AppID: "test1",
|
||||||
Ports: []int{80},
|
Ports: []int{80},
|
||||||
},
|
},
|
||||||
expected: "80",
|
expected: "80",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "test1",
|
||||||
|
},
|
||||||
|
},
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
|
AppID: "test1",
|
||||||
Ports: []int{80, 443},
|
Ports: []int{80, 443},
|
||||||
},
|
},
|
||||||
expected: "80",
|
expected: "80",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "specify-port-number",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"traefik.port": "443",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "specify-port-number",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
},
|
||||||
|
expected: "443",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "specify-port-index",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"traefik.portIndex": "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "specify-port-index",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
},
|
||||||
|
expected: "443",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
actual := provider.getPort(c.task)
|
actual := provider.getPort(c.task, c.applications)
|
||||||
if actual != c.expected {
|
if actual != c.expected {
|
||||||
t.Fatalf("expected %q, got %q", c.expected, actual)
|
t.Fatalf("expected %q, got %q", c.expected, actual)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{{$apps := .Applications}}
|
{{$apps := .Applications}}
|
||||||
[backends]{{range .Tasks}}
|
[backends]{{range .Tasks}}
|
||||||
[backends.backend{{.AppID | replace "/" "-"}}.servers.server-{{.ID | replace "." "-"}}]
|
[backends.backend{{.AppID | replace "/" "-"}}.servers.server-{{.ID | replace "." "-"}}]
|
||||||
url = "{{getProtocol . $apps}}://{{.Host}}:{{getPort .}}"
|
url = "{{getProtocol . $apps}}://{{.Host}}:{{getPort . $apps}}"
|
||||||
weight = {{getWeight . $apps}}
|
weight = {{getWeight . $apps}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
@ -12,4 +12,4 @@
|
||||||
[frontends.frontend{{.ID | replace "/" "-"}}.routes.route-host{{.ID | replace "/" "-"}}]
|
[frontends.frontend{{.ID | replace "/" "-"}}.routes.route-host{{.ID | replace "/" "-"}}]
|
||||||
rule = "{{getFrontendRule .}}"
|
rule = "{{getFrontendRule .}}"
|
||||||
value = "{{getFrontendValue .}}"
|
value = "{{getFrontendValue .}}"
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
Loading…
Reference in a new issue