diff --git a/docs/toml.md b/docs/toml.md index 9689fafa6..254280691 100644 --- a/docs/toml.md +++ b/docs/toml.md @@ -636,7 +636,16 @@ domain = "marathon.localhost" # Optional # Default: false # -# ExposedByDefault = true +# exposedByDefault = true + +# Convert Marathon groups to subdomains +# Default behavior: /foo/bar/myapp => foo-bar-myapp.{defaultDomain} +# with groupsAsSubDomains enabled: /foo/bar/myapp => myapp.bar.foo.{defaultDomain} +# +# Optional +# Default: false +# +# groupsAsSubDomains = true # Enable Marathon basic authentication # diff --git a/examples/whoami-group.json b/examples/whoami-group.json new file mode 100644 index 000000000..9c21a8dae --- /dev/null +++ b/examples/whoami-group.json @@ -0,0 +1,40 @@ +{ + "id": "/foo", + "groups": [ + { + "id": "/foo/bar", + "apps": [ + { + "id": "whoami", + "cpus": 0.1, + "mem": 64.0, + "instances": 3, + "container": { + "type": "DOCKER", + "docker": { + "image": "emilevauge/whoami", + "network": "BRIDGE", + "portMappings": [ + { + "containerPort": 80, + "hostPort": 0, + "protocol": "tcp" + } + ] + } + }, + "healthChecks": [ + { + "protocol": "HTTP", + "portIndex": 0, + "path": "/", + "gracePeriodSeconds": 5, + "intervalSeconds": 20, + "maxConsecutiveFailures": 3 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/provider/docker.go b/provider/docker.go index 542f244ab..657eabfda 100644 --- a/provider/docker.go +++ b/provider/docker.go @@ -236,7 +236,7 @@ func (provider *Docker) getFrontendRule(container dockertypes.ContainerJSON) str if label, err := getLabel(container, "traefik.frontend.rule"); err == nil { return label } - return "Host:" + getEscapedName(container.Name) + "." + provider.Domain + return "Host:" + provider.getSubDomain(container.Name) + "." + provider.Domain } func (provider *Docker) getBackend(container dockertypes.ContainerJSON) string { @@ -349,3 +349,8 @@ func listContainers(dockerClient client.APIClient) ([]dockertypes.ContainerJSON, } return containersInspected, nil } + +// Escape beginning slash "/", convert all others to dash "-" +func (provider *Docker) getSubDomain(name string) string { + return strings.Replace(strings.TrimPrefix(name, "/"), "/", "-", -1) +} diff --git a/provider/marathon.go b/provider/marathon.go index efdaaf238..a97e70ecb 100644 --- a/provider/marathon.go +++ b/provider/marathon.go @@ -3,6 +3,7 @@ package provider import ( "errors" "net/url" + "sort" "strconv" "strings" "text/template" @@ -20,13 +21,14 @@ import ( // Marathon holds configuration of the Marathon provider. type Marathon struct { - BaseProvider `mapstructure:",squash" description:"go through"` - Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon"` - Domain string `description:"Default domain used"` - ExposedByDefault bool `description:"Expose Marathon apps by default"` - Basic *MarathonBasic - TLS *tls.Config - marathonClient marathon.Marathon + BaseProvider + Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon"` + Domain string `description:"Default domain used"` + ExposedByDefault bool `description:"Expose Marathon apps by default"` + GroupsAsSubDomains bool `description:"Convert Marathon groups to subdomains"` + Basic *MarathonBasic + TLS *tls.Config + marathonClient marathon.Marathon } // MarathonBasic holds basic authentication specific configurations @@ -341,7 +343,7 @@ func (provider *Marathon) getFrontendRule(application marathon.Application) stri if label, err := provider.getLabel(application, "traefik.frontend.rule"); err == nil { return label } - return "Host:" + getEscapedName(application.ID) + "." + provider.Domain + return "Host:" + provider.getSubDomain(application.ID) + "." + provider.Domain } func (provider *Marathon) getBackend(task marathon.Task, applications []marathon.Application) string { @@ -359,3 +361,13 @@ func (provider *Marathon) getFrontendBackend(application marathon.Application) s } return replace("/", "-", application.ID) } + +func (provider *Marathon) getSubDomain(name string) string { + if provider.GroupsAsSubDomains { + splitedName := strings.Split(strings.TrimPrefix(name, "/"), "/") + sort.Sort(sort.Reverse(sort.StringSlice(splitedName))) + reverseName := strings.Join(splitedName, ".") + return reverseName + } + return strings.Replace(strings.TrimPrefix(name, "/"), "/", "-", -1) +} diff --git a/provider/provider.go b/provider/provider.go index fafc39c7e..5f52988e0 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -85,11 +85,6 @@ func replace(s1 string, s2 string, s3 string) string { return strings.Replace(s3, s1, s2, -1) } -// Escape beginning slash "/", convert all others to dash "-" -func getEscapedName(name string) string { - return strings.Replace(strings.TrimPrefix(name, "/"), "/", "-", -1) -} - func normalize(name string) string { fargs := func(c rune) bool { return !unicode.IsLetter(c) && !unicode.IsNumber(c) diff --git a/traefik.sample.toml b/traefik.sample.toml index 51f2442e4..3b900c112 100644 --- a/traefik.sample.toml +++ b/traefik.sample.toml @@ -306,7 +306,16 @@ # Optional # Default: false # -# ExposedByDefault = true +# exposedByDefault = true + +# Convert Marathon groups to subdomains +# Default behavior: /foo/bar/myapp => foo-bar-myapp.{defaultDomain} +# with groupsAsSubDomains enabled: /foo/bar/myapp => myapp.bar.foo.{defaultDomain} +# +# Optional +# Default: false +# +# groupsAsSubDomains = true # Enable Marathon basic authentication #