Merge pull request #1474 from containous/marathon-check-port-label-overwrite-earlier
Check for explicitly defined Marathon port first.
This commit is contained in:
commit
750fa22cff
3 changed files with 316 additions and 262 deletions
|
@ -2,6 +2,7 @@ package marathon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -22,6 +23,11 @@ import (
|
||||||
"github.com/gambol99/go-marathon"
|
"github.com/gambol99/go-marathon"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
labelPort = "traefik.port"
|
||||||
|
labelPortIndex = "traefik.portIndex"
|
||||||
|
)
|
||||||
|
|
||||||
var _ provider.Provider = (*Provider)(nil)
|
var _ provider.Provider = (*Provider)(nil)
|
||||||
|
|
||||||
// Provider holds configuration of the provider.
|
// Provider holds configuration of the provider.
|
||||||
|
@ -194,67 +200,55 @@ func (p *Provider) loadMarathonConfig() *types.Configuration {
|
||||||
func (p *Provider) taskFilter(task marathon.Task, applications *marathon.Applications, exposedByDefaultFlag bool) bool {
|
func (p *Provider) taskFilter(task marathon.Task, applications *marathon.Applications, exposedByDefaultFlag bool) bool {
|
||||||
application, err := getApplication(task, applications.Apps)
|
application, err := getApplication(task, applications.Apps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Unable to get marathon application from task %s", task.AppID)
|
log.Errorf("Unable to get Marathon application %s for task %s", task.AppID, task.ID)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
ports := processPorts(application, task)
|
if _, err = processPorts(application, task); err != nil {
|
||||||
if len(ports) == 0 {
|
log.Errorf("Filtering Marathon task %s from application %s without port: %s", task.ID, application.ID, err)
|
||||||
log.Debug("Filtering marathon task without port %s", task.AppID)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter illegal port label specification.
|
||||||
|
_, hasPortIndexLabel := p.getLabel(application, labelPortIndex)
|
||||||
|
_, hasPortLabel := p.getLabel(application, labelPort)
|
||||||
|
if hasPortIndexLabel && hasPortLabel {
|
||||||
|
log.Debugf("Filtering Marathon task %s from application %s specifying both traefik.portIndex and traefik.port labels", task.ID, application.ID)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter by constraints.
|
||||||
label, _ := p.getLabel(application, "traefik.tags")
|
label, _ := p.getLabel(application, "traefik.tags")
|
||||||
constraintTags := strings.Split(label, ",")
|
constraintTags := strings.Split(label, ",")
|
||||||
if p.MarathonLBCompatibility {
|
if p.MarathonLBCompatibility {
|
||||||
if label, err := p.getLabel(application, "HAPROXY_GROUP"); err == nil {
|
if label, ok := p.getLabel(application, "HAPROXY_GROUP"); ok {
|
||||||
constraintTags = append(constraintTags, label)
|
constraintTags = append(constraintTags, label)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ok, failingConstraint := p.MatchConstraints(constraintTags); !ok {
|
if ok, failingConstraint := p.MatchConstraints(constraintTags); !ok {
|
||||||
if failingConstraint != nil {
|
if failingConstraint != nil {
|
||||||
log.Debugf("Application %v pruned by '%v' constraint", application.ID, failingConstraint.String())
|
log.Debugf("Filtering Marathon task %s from application %s pruned by '%v' constraint", task.ID, application.ID, failingConstraint.String())
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter disabled application.
|
||||||
if !isApplicationEnabled(application, exposedByDefaultFlag) {
|
if !isApplicationEnabled(application, exposedByDefaultFlag) {
|
||||||
log.Debugf("Filtering disabled marathon task %s", task.AppID)
|
log.Debugf("Filtering disabled Marathon task %s from application %s", task.ID, application.ID)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
//filter indeterminable task port
|
// Filter task with existing, bad health check results.
|
||||||
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 != "" {
|
|
||||||
index, err := strconv.Atoi((*application.Labels)["traefik.portIndex"])
|
|
||||||
if err != nil || index < 0 || index > len(ports)-1 {
|
|
||||||
log.Debugf("Filtering marathon task %s with unexpected value for traefik.portIndex label", task.AppID)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if portValueLabel != "" {
|
|
||||||
_, 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//filter healthchecks
|
|
||||||
if application.HasHealthChecks() {
|
if application.HasHealthChecks() {
|
||||||
if task.HasHealthCheckResults() {
|
if task.HasHealthCheckResults() {
|
||||||
for _, healthcheck := range task.HealthCheckResults {
|
for _, healthcheck := range task.HealthCheckResults {
|
||||||
// found one bad healthcheck, return false
|
|
||||||
if !healthcheck.Alive {
|
if !healthcheck.Alive {
|
||||||
log.Debugf("Filtering marathon task %s with bad healthcheck", task.AppID)
|
log.Debugf("Filtering Marathon task %s from application %s with bad health check", task.ID, application.ID)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +256,7 @@ func (p *Provider) applicationFilter(app marathon.Application, filteredTasks []m
|
||||||
label, _ := p.getLabel(app, "traefik.tags")
|
label, _ := p.getLabel(app, "traefik.tags")
|
||||||
constraintTags := strings.Split(label, ",")
|
constraintTags := strings.Split(label, ",")
|
||||||
if p.MarathonLBCompatibility {
|
if p.MarathonLBCompatibility {
|
||||||
if label, err := p.getLabel(app, "HAPROXY_GROUP"); err == nil {
|
if label, ok := p.getLabel(app, "HAPROXY_GROUP"); ok {
|
||||||
constraintTags = append(constraintTags, label)
|
constraintTags = append(constraintTags, label)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,36 +285,29 @@ func isApplicationEnabled(application marathon.Application, exposedByDefault boo
|
||||||
return exposedByDefault && (*application.Labels)["traefik.enable"] != "false" || (*application.Labels)["traefik.enable"] == "true"
|
return exposedByDefault && (*application.Labels)["traefik.enable"] != "false" || (*application.Labels)["traefik.enable"] == "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getLabel(application marathon.Application, label string) (string, error) {
|
func (p *Provider) getLabel(application marathon.Application, label string) (string, bool) {
|
||||||
for key, value := range *application.Labels {
|
for key, value := range *application.Labels {
|
||||||
if key == label {
|
if key == label {
|
||||||
return value, nil
|
return value, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", errors.New("Label not found:" + label)
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getPort(task marathon.Task, applications []marathon.Application) string {
|
func (p *Provider) getPort(task marathon.Task, applications []marathon.Application) string {
|
||||||
application, err := getApplication(task, applications)
|
application, err := getApplication(task, applications)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Unable to get marathon application from task %s", task.AppID)
|
log.Errorf("Unable to get Marathon application %s for task %s", application.ID, task.ID)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
ports := processPorts(application, task)
|
port, err := processPorts(application, task)
|
||||||
if portIndexLabel, err := p.getLabel(application, "traefik.portIndex"); err == nil {
|
if err != nil {
|
||||||
if index, err := strconv.Atoi(portIndexLabel); err == nil {
|
log.Errorf("Unable to process ports for Marathon application %s and task %s: %s", application.ID, task.ID, err)
|
||||||
return strconv.Itoa(ports[index])
|
return ""
|
||||||
}
|
|
||||||
}
|
|
||||||
if portValueLabel, err := p.getLabel(application, "traefik.port"); err == nil {
|
|
||||||
return portValueLabel
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, port := range ports {
|
|
||||||
return strconv.Itoa(port)
|
return strconv.Itoa(port)
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Provider) getWeight(task marathon.Task, applications []marathon.Application) string {
|
func (p *Provider) getWeight(task marathon.Task, applications []marathon.Application) string {
|
||||||
application, errApp := getApplication(task, applications)
|
application, errApp := getApplication(task, applications)
|
||||||
|
@ -328,14 +315,14 @@ func (p *Provider) getWeight(task marathon.Task, applications []marathon.Applica
|
||||||
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 "0"
|
return "0"
|
||||||
}
|
}
|
||||||
if label, err := p.getLabel(application, "traefik.weight"); err == nil {
|
if label, ok := p.getLabel(application, "traefik.weight"); ok {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return "0"
|
return "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getDomain(application marathon.Application) string {
|
func (p *Provider) getDomain(application marathon.Application) string {
|
||||||
if label, err := p.getLabel(application, "traefik.domain"); err == nil {
|
if label, ok := p.getLabel(application, "traefik.domain"); ok {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return p.Domain
|
return p.Domain
|
||||||
|
@ -347,35 +334,35 @@ func (p *Provider) getProtocol(task marathon.Task, applications []marathon.Appli
|
||||||
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 "http"
|
return "http"
|
||||||
}
|
}
|
||||||
if label, err := p.getLabel(application, "traefik.protocol"); err == nil {
|
if label, ok := p.getLabel(application, "traefik.protocol"); ok {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return "http"
|
return "http"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getSticky(application marathon.Application) string {
|
func (p *Provider) getSticky(application marathon.Application) string {
|
||||||
if sticky, err := p.getLabel(application, "traefik.backend.loadbalancer.sticky"); err == nil {
|
if sticky, ok := p.getLabel(application, "traefik.backend.loadbalancer.sticky"); ok {
|
||||||
return sticky
|
return sticky
|
||||||
}
|
}
|
||||||
return "false"
|
return "false"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getPassHostHeader(application marathon.Application) string {
|
func (p *Provider) getPassHostHeader(application marathon.Application) string {
|
||||||
if passHostHeader, err := p.getLabel(application, "traefik.frontend.passHostHeader"); err == nil {
|
if passHostHeader, ok := p.getLabel(application, "traefik.frontend.passHostHeader"); ok {
|
||||||
return passHostHeader
|
return passHostHeader
|
||||||
}
|
}
|
||||||
return "true"
|
return "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getPriority(application marathon.Application) string {
|
func (p *Provider) getPriority(application marathon.Application) string {
|
||||||
if priority, err := p.getLabel(application, "traefik.frontend.priority"); err == nil {
|
if priority, ok := p.getLabel(application, "traefik.frontend.priority"); ok {
|
||||||
return priority
|
return priority
|
||||||
}
|
}
|
||||||
return "0"
|
return "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getEntryPoints(application marathon.Application) []string {
|
func (p *Provider) getEntryPoints(application marathon.Application) []string {
|
||||||
if entryPoints, err := p.getLabel(application, "traefik.frontend.entryPoints"); err == nil {
|
if entryPoints, ok := p.getLabel(application, "traefik.frontend.entryPoints"); ok {
|
||||||
return strings.Split(entryPoints, ",")
|
return strings.Split(entryPoints, ",")
|
||||||
}
|
}
|
||||||
return []string{}
|
return []string{}
|
||||||
|
@ -384,11 +371,11 @@ func (p *Provider) getEntryPoints(application marathon.Application) []string {
|
||||||
// getFrontendRule returns the frontend rule for the specified application, using
|
// getFrontendRule returns the frontend rule for the specified application, 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 (p *Provider) getFrontendRule(application marathon.Application) string {
|
func (p *Provider) getFrontendRule(application marathon.Application) string {
|
||||||
if label, err := p.getLabel(application, "traefik.frontend.rule"); err == nil {
|
if label, ok := p.getLabel(application, "traefik.frontend.rule"); ok {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
if p.MarathonLBCompatibility {
|
if p.MarathonLBCompatibility {
|
||||||
if label, err := p.getLabel(application, "HAPROXY_0_VHOST"); err == nil {
|
if label, ok := p.getLabel(application, "HAPROXY_0_VHOST"); ok {
|
||||||
return "Host:" + label
|
return "Host:" + label
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,7 +392,7 @@ func (p *Provider) getBackend(task marathon.Task, applications []marathon.Applic
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getFrontendBackend(application marathon.Application) string {
|
func (p *Provider) getFrontendBackend(application marathon.Application) string {
|
||||||
if label, err := p.getLabel(application, "traefik.backend"); err == nil {
|
if label, ok := p.getLabel(application, "traefik.backend"); ok {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return provider.Replace("/", "-", application.ID)
|
return provider.Replace("/", "-", application.ID)
|
||||||
|
@ -422,33 +409,26 @@ func (p *Provider) getSubDomain(name string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) hasCircuitBreakerLabels(application marathon.Application) bool {
|
func (p *Provider) hasCircuitBreakerLabels(application marathon.Application) bool {
|
||||||
if _, err := p.getLabel(application, "traefik.backend.circuitbreaker.expression"); err != nil {
|
_, ok := p.getLabel(application, "traefik.backend.circuitbreaker.expression")
|
||||||
return false
|
return ok
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) hasLoadBalancerLabels(application marathon.Application) bool {
|
func (p *Provider) hasLoadBalancerLabels(application marathon.Application) bool {
|
||||||
_, errMethod := p.getLabel(application, "traefik.backend.loadbalancer.method")
|
_, errMethod := p.getLabel(application, "traefik.backend.loadbalancer.method")
|
||||||
_, errSticky := p.getLabel(application, "traefik.backend.loadbalancer.sticky")
|
_, errSticky := p.getLabel(application, "traefik.backend.loadbalancer.sticky")
|
||||||
if errMethod != nil && errSticky != nil {
|
return errMethod || errSticky
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) hasMaxConnLabels(application marathon.Application) bool {
|
func (p *Provider) hasMaxConnLabels(application marathon.Application) bool {
|
||||||
if _, err := p.getLabel(application, "traefik.backend.maxconn.amount"); err != nil {
|
if _, ok := p.getLabel(application, "traefik.backend.maxconn.amount"); !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if _, err := p.getLabel(application, "traefik.backend.maxconn.extractorfunc"); err != nil {
|
_, ok := p.getLabel(application, "traefik.backend.maxconn.extractorfunc")
|
||||||
return false
|
return ok
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getMaxConnAmount(application marathon.Application) int64 {
|
func (p *Provider) getMaxConnAmount(application marathon.Application) int64 {
|
||||||
if label, err := p.getLabel(application, "traefik.backend.maxconn.amount"); err == nil {
|
if label, ok := p.getLabel(application, "traefik.backend.maxconn.amount"); ok {
|
||||||
i, errConv := strconv.ParseInt(label, 10, 64)
|
i, errConv := strconv.ParseInt(label, 10, 64)
|
||||||
if errConv != nil {
|
if errConv != nil {
|
||||||
log.Errorf("Unable to parse traefik.backend.maxconn.amount %s", label)
|
log.Errorf("Unable to parse traefik.backend.maxconn.amount %s", label)
|
||||||
|
@ -460,28 +440,59 @@ func (p *Provider) getMaxConnAmount(application marathon.Application) int64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getMaxConnExtractorFunc(application marathon.Application) string {
|
func (p *Provider) getMaxConnExtractorFunc(application marathon.Application) string {
|
||||||
if label, err := p.getLabel(application, "traefik.backend.maxconn.extractorfunc"); err == nil {
|
if label, ok := p.getLabel(application, "traefik.backend.maxconn.extractorfunc"); ok {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return "request.host"
|
return "request.host"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getLoadBalancerMethod(application marathon.Application) string {
|
func (p *Provider) getLoadBalancerMethod(application marathon.Application) string {
|
||||||
if label, err := p.getLabel(application, "traefik.backend.loadbalancer.method"); err == nil {
|
if label, ok := p.getLabel(application, "traefik.backend.loadbalancer.method"); ok {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return "wrr"
|
return "wrr"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getCircuitBreakerExpression(application marathon.Application) string {
|
func (p *Provider) getCircuitBreakerExpression(application marathon.Application) string {
|
||||||
if label, err := p.getLabel(application, "traefik.backend.circuitbreaker.expression"); err == nil {
|
if label, ok := p.getLabel(application, "traefik.backend.circuitbreaker.expression"); ok {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return "NetworkErrorRatio() > 1"
|
return "NetworkErrorRatio() > 1"
|
||||||
}
|
}
|
||||||
|
|
||||||
func processPorts(application marathon.Application, task marathon.Task) []int {
|
func processPorts(application marathon.Application, task marathon.Task) (int, error) {
|
||||||
|
if portLabel, ok := (*application.Labels)[labelPort]; ok {
|
||||||
|
port, err := strconv.Atoi(portLabel)
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
return 0, fmt.Errorf("failed to parse port label: %s", err)
|
||||||
|
case port <= 0:
|
||||||
|
return 0, fmt.Errorf("explicitly specified port %d must be larger than zero", port)
|
||||||
|
}
|
||||||
|
return port, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ports := retrieveAvailablePorts(application, task)
|
||||||
|
if len(ports) == 0 {
|
||||||
|
return 0, errors.New("no port found")
|
||||||
|
}
|
||||||
|
|
||||||
|
portIndex := 0
|
||||||
|
portIndexLabel, ok := (*application.Labels)[labelPortIndex]
|
||||||
|
if ok {
|
||||||
|
var err error
|
||||||
|
portIndex, err = strconv.Atoi(portIndexLabel)
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
return 0, fmt.Errorf("failed to parse port index label: %s", err)
|
||||||
|
case portIndex < 0, portIndex > len(ports)-1:
|
||||||
|
return 0, fmt.Errorf("port index %d must be within port range (0, %d)", portIndex, len(ports)-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ports[portIndex], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func retrieveAvailablePorts(application marathon.Application, task marathon.Task) []int {
|
||||||
// Using default port configuration
|
// Using default port configuration
|
||||||
if task.Ports != nil && len(task.Ports) > 0 {
|
if task.Ports != nil && len(task.Ports) > 0 {
|
||||||
return task.Ports
|
return task.Ports
|
||||||
|
@ -520,8 +531,8 @@ func (p *Provider) getBackendServer(task marathon.Task, applications []marathon.
|
||||||
} else if len(task.IPAddresses) == 1 {
|
} else if len(task.IPAddresses) == 1 {
|
||||||
return task.IPAddresses[0].IPAddress
|
return task.IPAddresses[0].IPAddress
|
||||||
} else {
|
} else {
|
||||||
ipAddressIdxStr, err := p.getLabel(application, "traefik.ipAddressIdx")
|
ipAddressIdxStr, ok := p.getLabel(application, "traefik.ipAddressIdx")
|
||||||
if err != nil {
|
if !ok {
|
||||||
log.Errorf("Unable to get marathon IPAddress from task %s", task.AppID)
|
log.Errorf("Unable to get marathon IPAddress from task %s", task.AppID)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containous/traefik/mocks"
|
"github.com/containous/traefik/mocks"
|
||||||
|
"github.com/containous/traefik/testhelpers"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/gambol99/go-marathon"
|
"github.com/gambol99/go-marathon"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
|
@ -400,39 +401,30 @@ func TestMarathonTaskFilter(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "multiple-ports",
|
AppID: "missing-port",
|
||||||
Ports: []int{80, 443},
|
Ports: []int{},
|
||||||
},
|
},
|
||||||
applications: &marathon.Applications{
|
applications: &marathon.Applications{
|
||||||
Apps: []marathon.Application{
|
Apps: []marathon.Application{
|
||||||
{
|
{
|
||||||
ID: "multiple-ports",
|
ID: "missing-port",
|
||||||
Ports: []int{80, 443},
|
|
||||||
Labels: &map[string]string{},
|
Labels: &map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: true,
|
expected: false,
|
||||||
exposedByDefault: true,
|
exposedByDefault: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "ipAddressOnePort",
|
AppID: "existing-port",
|
||||||
|
Ports: []int{80},
|
||||||
},
|
},
|
||||||
applications: &marathon.Applications{
|
applications: &marathon.Applications{
|
||||||
Apps: []marathon.Application{
|
Apps: []marathon.Application{
|
||||||
{
|
{
|
||||||
ID: "ipAddressOnePort",
|
ID: "existing-port",
|
||||||
IPAddressPerTask: &marathon.IPAddressPerTask{
|
Ports: []int{80},
|
||||||
Discovery: &marathon.Discovery{
|
|
||||||
Ports: &[]marathon.Port{
|
|
||||||
{
|
|
||||||
Number: 8880,
|
|
||||||
Name: "p1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Labels: &map[string]string{},
|
Labels: &map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -440,64 +432,6 @@ func TestMarathonTaskFilter(t *testing.T) {
|
||||||
expected: true,
|
expected: true,
|
||||||
exposedByDefault: true,
|
exposedByDefault: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
task: marathon.Task{
|
|
||||||
AppID: "ipAddressTwoPortsUseFirst",
|
|
||||||
},
|
|
||||||
applications: &marathon.Applications{
|
|
||||||
Apps: []marathon.Application{
|
|
||||||
{
|
|
||||||
ID: "ipAddressTwoPortsUseFirst",
|
|
||||||
IPAddressPerTask: &marathon.IPAddressPerTask{
|
|
||||||
Discovery: &marathon.Discovery{
|
|
||||||
Ports: &[]marathon.Port{
|
|
||||||
{
|
|
||||||
Number: 8898,
|
|
||||||
Name: "p1",
|
|
||||||
}, {
|
|
||||||
Number: 9999,
|
|
||||||
Name: "p1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Labels: &map[string]string{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: true,
|
|
||||||
exposedByDefault: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
task: marathon.Task{
|
|
||||||
AppID: "ipAddressValidTwoPorts",
|
|
||||||
},
|
|
||||||
applications: &marathon.Applications{
|
|
||||||
Apps: []marathon.Application{
|
|
||||||
{
|
|
||||||
ID: "ipAddressValidTwoPorts",
|
|
||||||
IPAddressPerTask: &marathon.IPAddressPerTask{
|
|
||||||
Discovery: &marathon.Discovery{
|
|
||||||
Ports: &[]marathon.Port{
|
|
||||||
{
|
|
||||||
Number: 8898,
|
|
||||||
Name: "p1",
|
|
||||||
}, {
|
|
||||||
Number: 9999,
|
|
||||||
Name: "p2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Labels: &map[string]string{
|
|
||||||
"traefik.portIndex": "0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: true,
|
|
||||||
exposedByDefault: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
Ports: []int{80},
|
Ports: []int{80},
|
||||||
|
@ -516,62 +450,6 @@ func TestMarathonTaskFilter(t *testing.T) {
|
||||||
expected: false,
|
expected: false,
|
||||||
exposedByDefault: true,
|
exposedByDefault: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
task: marathon.Task{
|
|
||||||
AppID: "specify-port-number",
|
|
||||||
Ports: []int{80},
|
|
||||||
},
|
|
||||||
applications: &marathon.Applications{
|
|
||||||
Apps: []marathon.Application{
|
|
||||||
{
|
|
||||||
ID: "specify-port-number",
|
|
||||||
Labels: &map[string]string{
|
|
||||||
"traefik.port": "8080",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: true,
|
|
||||||
exposedByDefault: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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,
|
|
||||||
exposedByDefault: 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,
|
|
||||||
exposedByDefault: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "specify-both-port-index-and-number",
|
AppID: "specify-both-port-index-and-number",
|
||||||
|
@ -594,13 +472,13 @@ func TestMarathonTaskFilter(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "foo",
|
AppID: "healthcheck-available",
|
||||||
Ports: []int{80},
|
Ports: []int{80},
|
||||||
},
|
},
|
||||||
applications: &marathon.Applications{
|
applications: &marathon.Applications{
|
||||||
Apps: []marathon.Application{
|
Apps: []marathon.Application{
|
||||||
{
|
{
|
||||||
ID: "foo",
|
ID: "healthcheck-available",
|
||||||
Ports: []int{80},
|
Ports: []int{80},
|
||||||
Labels: &map[string]string{},
|
Labels: &map[string]string{},
|
||||||
HealthChecks: &[]marathon.HealthCheck{
|
HealthChecks: &[]marathon.HealthCheck{
|
||||||
|
@ -639,7 +517,7 @@ func TestMarathonTaskFilter(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "foo",
|
AppID: "healthcheck-mixed-results",
|
||||||
Ports: []int{80},
|
Ports: []int{80},
|
||||||
HealthCheckResults: []*marathon.HealthCheckResult{
|
HealthCheckResults: []*marathon.HealthCheckResult{
|
||||||
{
|
{
|
||||||
|
@ -653,7 +531,7 @@ func TestMarathonTaskFilter(t *testing.T) {
|
||||||
applications: &marathon.Applications{
|
applications: &marathon.Applications{
|
||||||
Apps: []marathon.Application{
|
Apps: []marathon.Application{
|
||||||
{
|
{
|
||||||
ID: "foo",
|
ID: "healthcheck-mixed-results",
|
||||||
Ports: []int{80},
|
Ports: []int{80},
|
||||||
Labels: &map[string]string{},
|
Labels: &map[string]string{},
|
||||||
HealthChecks: &[]marathon.HealthCheck{
|
HealthChecks: &[]marathon.HealthCheck{
|
||||||
|
@ -665,23 +543,6 @@ func TestMarathonTaskFilter(t *testing.T) {
|
||||||
expected: false,
|
expected: false,
|
||||||
exposedByDefault: true,
|
exposedByDefault: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
task: marathon.Task{
|
|
||||||
AppID: "single-port",
|
|
||||||
Ports: []int{80},
|
|
||||||
},
|
|
||||||
applications: &marathon.Applications{
|
|
||||||
Apps: []marathon.Application{
|
|
||||||
{
|
|
||||||
ID: "single-port",
|
|
||||||
Ports: []int{80},
|
|
||||||
Labels: &map[string]string{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: true,
|
|
||||||
exposedByDefault: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "healthcheck-alive",
|
AppID: "healthcheck-alive",
|
||||||
|
@ -981,16 +842,22 @@ func TestMarathonGetPort(t *testing.T) {
|
||||||
provider := &Provider{}
|
provider := &Provider{}
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
desc string
|
||||||
applications []marathon.Application
|
applications []marathon.Application
|
||||||
task marathon.Task
|
task marathon.Task
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
desc: "no applications",
|
||||||
applications: []marathon.Application{},
|
applications: []marathon.Application{},
|
||||||
task: marathon.Task{},
|
task: marathon.Task{
|
||||||
|
AppID: "app",
|
||||||
|
Ports: []int{80},
|
||||||
|
},
|
||||||
expected: "",
|
expected: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
desc: "application mismatch",
|
||||||
applications: []marathon.Application{
|
applications: []marathon.Application{
|
||||||
{
|
{
|
||||||
ID: "test1",
|
ID: "test1",
|
||||||
|
@ -999,74 +866,240 @@ func TestMarathonGetPort(t *testing.T) {
|
||||||
},
|
},
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "test2",
|
AppID: "test2",
|
||||||
|
Ports: []int{80},
|
||||||
},
|
},
|
||||||
expected: "",
|
expected: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
desc: "port missing",
|
||||||
applications: []marathon.Application{
|
applications: []marathon.Application{
|
||||||
{
|
{
|
||||||
ID: "test1",
|
ID: "app",
|
||||||
Labels: &map[string]string{},
|
Labels: &map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "test1",
|
AppID: "app",
|
||||||
|
Ports: []int{},
|
||||||
|
},
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "explicit port taken",
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "app",
|
||||||
|
Labels: &map[string]string{
|
||||||
|
"traefik.port": "80",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "app",
|
||||||
|
Ports: []int{},
|
||||||
|
},
|
||||||
|
expected: "80",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "illegal explicit port specified",
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "app",
|
||||||
|
Labels: &map[string]string{
|
||||||
|
"traefik.port": "foobar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "app",
|
||||||
|
Ports: []int{80},
|
||||||
|
},
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "illegal explicit port integer specified",
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "app",
|
||||||
|
Labels: &map[string]string{
|
||||||
|
"traefik.port": "-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "app",
|
||||||
|
Ports: []int{80},
|
||||||
|
},
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "task port available",
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "app",
|
||||||
|
Labels: &map[string]string{},
|
||||||
|
PortDefinitions: &[]marathon.PortDefinition{
|
||||||
|
{
|
||||||
|
Port: testhelpers.Intp(443),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
IPAddressPerTask: &marathon.IPAddressPerTask{
|
||||||
|
Discovery: &marathon.Discovery{
|
||||||
|
Ports: &[]marathon.Port{
|
||||||
|
{
|
||||||
|
Number: 8000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "app",
|
||||||
Ports: []int{80},
|
Ports: []int{80},
|
||||||
},
|
},
|
||||||
expected: "80",
|
expected: "80",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
desc: "port mapping port available",
|
||||||
applications: []marathon.Application{
|
applications: []marathon.Application{
|
||||||
{
|
{
|
||||||
ID: "multiple-ports-take-first",
|
ID: "app",
|
||||||
|
Labels: &map[string]string{},
|
||||||
|
PortDefinitions: &[]marathon.PortDefinition{
|
||||||
|
{
|
||||||
|
Port: testhelpers.Intp(443),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
IPAddressPerTask: &marathon.IPAddressPerTask{
|
||||||
|
Discovery: &marathon.Discovery{
|
||||||
|
Ports: &[]marathon.Port{
|
||||||
|
{
|
||||||
|
Number: 8000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "app",
|
||||||
|
Ports: []int{},
|
||||||
|
},
|
||||||
|
expected: "443",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "IP-per-task port available",
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "app",
|
||||||
|
Labels: &map[string]string{},
|
||||||
|
IPAddressPerTask: &marathon.IPAddressPerTask{
|
||||||
|
Discovery: &marathon.Discovery{
|
||||||
|
Ports: &[]marathon.Port{
|
||||||
|
{
|
||||||
|
Number: 8000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "app",
|
||||||
|
Ports: []int{},
|
||||||
|
},
|
||||||
|
expected: "8000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "first port taken from multiple ports",
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "app",
|
||||||
Labels: &map[string]string{},
|
Labels: &map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "multiple-ports-take-first",
|
AppID: "app",
|
||||||
Ports: []int{80, 443},
|
Ports: []int{80, 443},
|
||||||
},
|
},
|
||||||
expected: "80",
|
expected: "80",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
desc: "indexed port taken",
|
||||||
applications: []marathon.Application{
|
applications: []marathon.Application{
|
||||||
{
|
{
|
||||||
ID: "specify-port-number",
|
ID: "app",
|
||||||
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{
|
Labels: &map[string]string{
|
||||||
"traefik.portIndex": "1",
|
"traefik.portIndex": "1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "specify-port-index",
|
AppID: "app",
|
||||||
Ports: []int{80, 443},
|
Ports: []int{80, 443},
|
||||||
},
|
},
|
||||||
expected: "443",
|
expected: "443",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
|
desc: "illegal port index specified",
|
||||||
applications: []marathon.Application{
|
applications: []marathon.Application{
|
||||||
{
|
{
|
||||||
ID: "application-with-port",
|
ID: "app",
|
||||||
|
Labels: &map[string]string{
|
||||||
|
"traefik.portIndex": "foobar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "app",
|
||||||
|
Ports: []int{80},
|
||||||
|
},
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sub-zero port index specified",
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "app",
|
||||||
|
Labels: &map[string]string{
|
||||||
|
"traefik.portIndex": "-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "app",
|
||||||
|
Ports: []int{80},
|
||||||
|
},
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "too high port index specified",
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "app",
|
||||||
|
Labels: &map[string]string{
|
||||||
|
"traefik.portIndex": "42",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
task: marathon.Task{
|
||||||
|
AppID: "app",
|
||||||
|
Ports: []int{80, 443},
|
||||||
|
},
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "task port preferred over application port",
|
||||||
|
applications: []marathon.Application{
|
||||||
|
{
|
||||||
|
ID: "app",
|
||||||
Ports: []int{9999},
|
Ports: []int{9999},
|
||||||
Labels: &map[string]string{},
|
Labels: &map[string]string{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
task: marathon.Task{
|
task: marathon.Task{
|
||||||
AppID: "application-with-port",
|
AppID: "app",
|
||||||
Ports: []int{7777},
|
Ports: []int{7777},
|
||||||
},
|
},
|
||||||
expected: "7777",
|
expected: "7777",
|
||||||
|
@ -1074,14 +1107,18 @@ func TestMarathonGetPort(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
|
c := c
|
||||||
|
t.Run(c.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
actual := provider.getPort(c.task, c.applications)
|
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.Errorf("got %q, want %q", c.expected, actual)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarathonGetWeigh(t *testing.T) {
|
func TestMarathonGetWeight(t *testing.T) {
|
||||||
provider := &Provider{}
|
provider := &Provider{}
|
||||||
|
|
||||||
applications := []struct {
|
applications := []struct {
|
||||||
|
|
6
testhelpers/helpers.go
Normal file
6
testhelpers/helpers.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package testhelpers
|
||||||
|
|
||||||
|
// Intp returns a pointer to the given integer value.
|
||||||
|
func Intp(i int) *int {
|
||||||
|
return &i
|
||||||
|
}
|
Loading…
Reference in a new issue