feat: custom label shorthands
This commit is contained in:
parent
c826cc97e6
commit
b4ef1baf65
8 changed files with 144 additions and 16 deletions
|
@ -768,6 +768,18 @@ Expose containers by default. (Default: ```true```)
|
||||||
`--providers.docker.httpclienttimeout`:
|
`--providers.docker.httpclienttimeout`:
|
||||||
Client timeout for HTTP connections. (Default: ```0```)
|
Client timeout for HTTP connections. (Default: ```0```)
|
||||||
|
|
||||||
|
`--providers.docker.labelmap`:
|
||||||
|
Label shorthands.
|
||||||
|
|
||||||
|
`--providers.docker.labelmap[n].from`:
|
||||||
|
Shorthand label.
|
||||||
|
|
||||||
|
`--providers.docker.labelmap[n].to`:
|
||||||
|
Full label with templates.
|
||||||
|
|
||||||
|
`--providers.docker.labelmap[n].value`:
|
||||||
|
Optional override; used instead of user input if set.
|
||||||
|
|
||||||
`--providers.docker.network`:
|
`--providers.docker.network`:
|
||||||
Default Docker network used.
|
Default Docker network used.
|
||||||
|
|
||||||
|
@ -1167,6 +1179,18 @@ Expose containers by default. (Default: ```true```)
|
||||||
`--providers.swarm.httpclienttimeout`:
|
`--providers.swarm.httpclienttimeout`:
|
||||||
Client timeout for HTTP connections. (Default: ```0```)
|
Client timeout for HTTP connections. (Default: ```0```)
|
||||||
|
|
||||||
|
`--providers.swarm.labelmap`:
|
||||||
|
Label shorthands.
|
||||||
|
|
||||||
|
`--providers.swarm.labelmap[n].from`:
|
||||||
|
Shorthand label.
|
||||||
|
|
||||||
|
`--providers.swarm.labelmap[n].to`:
|
||||||
|
Full label with templates.
|
||||||
|
|
||||||
|
`--providers.swarm.labelmap[n].value`:
|
||||||
|
Optional override; used instead of user input if set.
|
||||||
|
|
||||||
`--providers.swarm.network`:
|
`--providers.swarm.network`:
|
||||||
Default Docker network used.
|
Default Docker network used.
|
||||||
|
|
||||||
|
|
|
@ -768,6 +768,18 @@ Expose containers by default. (Default: ```true```)
|
||||||
`TRAEFIK_PROVIDERS_DOCKER_HTTPCLIENTTIMEOUT`:
|
`TRAEFIK_PROVIDERS_DOCKER_HTTPCLIENTTIMEOUT`:
|
||||||
Client timeout for HTTP connections. (Default: ```0```)
|
Client timeout for HTTP connections. (Default: ```0```)
|
||||||
|
|
||||||
|
`TRAEFIK_PROVIDERS_DOCKER_LABELMAP`:
|
||||||
|
Label shorthands.
|
||||||
|
|
||||||
|
`TRAEFIK_PROVIDERS_DOCKER_LABELMAP_n_FROM`:
|
||||||
|
Shorthand label.
|
||||||
|
|
||||||
|
`TRAEFIK_PROVIDERS_DOCKER_LABELMAP_n_TO`:
|
||||||
|
Full label with templates.
|
||||||
|
|
||||||
|
`TRAEFIK_PROVIDERS_DOCKER_LABELMAP_n_VALUE`:
|
||||||
|
Optional override; used instead of user input if set.
|
||||||
|
|
||||||
`TRAEFIK_PROVIDERS_DOCKER_NETWORK`:
|
`TRAEFIK_PROVIDERS_DOCKER_NETWORK`:
|
||||||
Default Docker network used.
|
Default Docker network used.
|
||||||
|
|
||||||
|
@ -1167,6 +1179,18 @@ Expose containers by default. (Default: ```true```)
|
||||||
`TRAEFIK_PROVIDERS_SWARM_HTTPCLIENTTIMEOUT`:
|
`TRAEFIK_PROVIDERS_SWARM_HTTPCLIENTTIMEOUT`:
|
||||||
Client timeout for HTTP connections. (Default: ```0```)
|
Client timeout for HTTP connections. (Default: ```0```)
|
||||||
|
|
||||||
|
`TRAEFIK_PROVIDERS_SWARM_LABELMAP`:
|
||||||
|
Label shorthands.
|
||||||
|
|
||||||
|
`TRAEFIK_PROVIDERS_SWARM_LABELMAP_n_FROM`:
|
||||||
|
Shorthand label.
|
||||||
|
|
||||||
|
`TRAEFIK_PROVIDERS_SWARM_LABELMAP_n_TO`:
|
||||||
|
Full label with templates.
|
||||||
|
|
||||||
|
`TRAEFIK_PROVIDERS_SWARM_LABELMAP_n_VALUE`:
|
||||||
|
Optional override; used instead of user input if set.
|
||||||
|
|
||||||
`TRAEFIK_PROVIDERS_SWARM_NETWORK`:
|
`TRAEFIK_PROVIDERS_SWARM_NETWORK`:
|
||||||
Default Docker network used.
|
Default Docker network used.
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,16 @@
|
||||||
password = "foobar"
|
password = "foobar"
|
||||||
endpoint = "foobar"
|
endpoint = "foobar"
|
||||||
httpClientTimeout = "42s"
|
httpClientTimeout = "42s"
|
||||||
|
|
||||||
|
[[providers.docker.labelMap]]
|
||||||
|
from = "foobar"
|
||||||
|
to = "foobar"
|
||||||
|
value = "foobar"
|
||||||
|
|
||||||
|
[[providers.docker.labelMap]]
|
||||||
|
from = "foobar"
|
||||||
|
to = "foobar"
|
||||||
|
value = "foobar"
|
||||||
[providers.docker.tls]
|
[providers.docker.tls]
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
cert = "foobar"
|
cert = "foobar"
|
||||||
|
@ -116,6 +126,16 @@
|
||||||
endpoint = "foobar"
|
endpoint = "foobar"
|
||||||
httpClientTimeout = "42s"
|
httpClientTimeout = "42s"
|
||||||
refreshSeconds = "42s"
|
refreshSeconds = "42s"
|
||||||
|
|
||||||
|
[[providers.swarm.labelMap]]
|
||||||
|
from = "foobar"
|
||||||
|
to = "foobar"
|
||||||
|
value = "foobar"
|
||||||
|
|
||||||
|
[[providers.swarm.labelMap]]
|
||||||
|
from = "foobar"
|
||||||
|
to = "foobar"
|
||||||
|
value = "foobar"
|
||||||
[providers.swarm.tls]
|
[providers.swarm.tls]
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
cert = "foobar"
|
cert = "foobar"
|
||||||
|
|
|
@ -109,6 +109,13 @@ providers:
|
||||||
useBindPortIP: true
|
useBindPortIP: true
|
||||||
watch: true
|
watch: true
|
||||||
defaultRule: foobar
|
defaultRule: foobar
|
||||||
|
labelMap:
|
||||||
|
- from: foobar
|
||||||
|
to: foobar
|
||||||
|
value: foobar
|
||||||
|
- from: foobar
|
||||||
|
to: foobar
|
||||||
|
value: foobar
|
||||||
username: foobar
|
username: foobar
|
||||||
password: foobar
|
password: foobar
|
||||||
endpoint: foobar
|
endpoint: foobar
|
||||||
|
@ -126,6 +133,13 @@ providers:
|
||||||
useBindPortIP: true
|
useBindPortIP: true
|
||||||
watch: true
|
watch: true
|
||||||
defaultRule: foobar
|
defaultRule: foobar
|
||||||
|
labelMap:
|
||||||
|
- from: foobar
|
||||||
|
to: foobar
|
||||||
|
value: foobar
|
||||||
|
- from: foobar
|
||||||
|
to: foobar
|
||||||
|
value: foobar
|
||||||
username: foobar
|
username: foobar
|
||||||
password: foobar
|
password: foobar
|
||||||
endpoint: foobar
|
endpoint: foobar
|
||||||
|
|
|
@ -396,8 +396,8 @@ func AddStore(configuration *dynamic.TLSConfiguration, storeName string, store t
|
||||||
return reflect.DeepEqual(configuration.Stores[storeName], store)
|
return reflect.DeepEqual(configuration.Stores[storeName], store)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeDefaultRuleTemplate creates the default rule template.
|
// MakeAnyTemplate creates a template with any name
|
||||||
func MakeDefaultRuleTemplate(defaultRule string, funcMap template.FuncMap) (*template.Template, error) {
|
func MakeAnyTemplate(name string, value string, funcMap template.FuncMap) (*template.Template, error) {
|
||||||
defaultFuncMap := sprig.TxtFuncMap()
|
defaultFuncMap := sprig.TxtFuncMap()
|
||||||
defaultFuncMap["normalize"] = Normalize
|
defaultFuncMap["normalize"] = Normalize
|
||||||
|
|
||||||
|
@ -405,7 +405,12 @@ func MakeDefaultRuleTemplate(defaultRule string, funcMap template.FuncMap) (*tem
|
||||||
defaultFuncMap[k] = fn
|
defaultFuncMap[k] = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
return template.New("defaultRule").Funcs(defaultFuncMap).Parse(defaultRule)
|
return template.New(name).Funcs(defaultFuncMap).Parse(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeDefaultRuleTemplate creates the default rule template.
|
||||||
|
func MakeDefaultRuleTemplate(defaultRule string, funcMap template.FuncMap) (*template.Template, error) {
|
||||||
|
return MakeAnyTemplate("defaultRule", defaultRule, funcMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildTCPRouterConfiguration builds a router configuration.
|
// BuildTCPRouterConfiguration builds a router configuration.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package docker
|
package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -28,15 +29,50 @@ func NewDynConfBuilder(configuration Shared, apiClient client.APIClient, swarm b
|
||||||
return &DynConfBuilder{Shared: configuration, apiClient: apiClient, swarm: swarm}
|
return &DynConfBuilder{Shared: configuration, apiClient: apiClient, swarm: swarm}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *DynConfBuilder) applyLabels(container *dockerData, model interface{}) {
|
||||||
|
for _, item := range p.LabelMap {
|
||||||
|
value, ok := container.Labels[item.From]
|
||||||
|
if !ok { // label doesn't exist
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
writer := &bytes.Buffer{}
|
||||||
|
if err := item.toTpl.Execute(writer, model); err != nil {
|
||||||
|
continue // should never happen?
|
||||||
|
}
|
||||||
|
|
||||||
|
to := writer.String()
|
||||||
|
if item.Value != nil {
|
||||||
|
container.Labels[to] = *item.Value
|
||||||
|
} else {
|
||||||
|
container.Labels[to] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *DynConfBuilder) build(ctx context.Context, containersInspected []dockerData) *dynamic.Configuration {
|
func (p *DynConfBuilder) build(ctx context.Context, containersInspected []dockerData) *dynamic.Configuration {
|
||||||
configurations := make(map[string]*dynamic.Configuration)
|
configurations := make(map[string]*dynamic.Configuration)
|
||||||
|
|
||||||
for _, container := range containersInspected {
|
for _, container := range containersInspected {
|
||||||
|
serviceName := getServiceName(container)
|
||||||
|
|
||||||
|
model := struct {
|
||||||
|
Name string
|
||||||
|
ContainerName string
|
||||||
|
Labels *map[string]string
|
||||||
|
}{
|
||||||
|
Name: serviceName,
|
||||||
|
ContainerName: strings.TrimPrefix(container.Name, "/"),
|
||||||
|
Labels: &container.Labels,
|
||||||
|
}
|
||||||
|
|
||||||
containerName := getServiceName(container) + "-" + container.ID
|
containerName := getServiceName(container) + "-" + container.ID
|
||||||
|
|
||||||
logger := log.Ctx(ctx).With().Str("container", containerName).Logger()
|
logger := log.Ctx(ctx).With().Str("container", containerName).Logger()
|
||||||
ctxContainer := logger.WithContext(ctx)
|
ctxContainer := logger.WithContext(ctx)
|
||||||
|
|
||||||
|
p.applyLabels(&container, model)
|
||||||
|
|
||||||
if !p.keepContainer(ctxContainer, container) {
|
if !p.keepContainer(ctxContainer, container) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -83,18 +119,6 @@ func (p *DynConfBuilder) build(ctx context.Context, containersInspected []docker
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceName := getServiceName(container)
|
|
||||||
|
|
||||||
model := struct {
|
|
||||||
Name string
|
|
||||||
ContainerName string
|
|
||||||
Labels map[string]string
|
|
||||||
}{
|
|
||||||
Name: serviceName,
|
|
||||||
ContainerName: strings.TrimPrefix(container.Name, "/"),
|
|
||||||
Labels: container.Labels,
|
|
||||||
}
|
|
||||||
|
|
||||||
provider.BuildRouterConfiguration(ctx, confFromLabel.HTTP, serviceName, p.defaultRuleTpl, model)
|
provider.BuildRouterConfiguration(ctx, confFromLabel.HTTP, serviceName, p.defaultRuleTpl, model)
|
||||||
|
|
||||||
configurations[containerName] = confFromLabel
|
configurations[containerName] = confFromLabel
|
||||||
|
|
|
@ -49,8 +49,15 @@ func (p *Provider) Init() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error while parsing default rule: %w", err)
|
return fmt.Errorf("error while parsing default rule: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.defaultRuleTpl = defaultRuleTpl
|
p.defaultRuleTpl = defaultRuleTpl
|
||||||
|
|
||||||
|
for _, item := range p.LabelMap {
|
||||||
|
toTpl, err := provider.MakeAnyTemplate(item.From, item.To, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while parsing label %v: %w", item.To, err)
|
||||||
|
}
|
||||||
|
item.toTpl = toTpl
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,19 @@ type Shared struct {
|
||||||
Watch bool `description:"Watch Docker events." json:"watch,omitempty" toml:"watch,omitempty" yaml:"watch,omitempty" export:"true"`
|
Watch bool `description:"Watch Docker events." json:"watch,omitempty" toml:"watch,omitempty" yaml:"watch,omitempty" export:"true"`
|
||||||
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
|
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
|
||||||
|
|
||||||
|
LabelMap []*LabelMapItem `description:"Label shorthands." json:"labelMap,omitempty" toml:"labelMap,omitempty" yaml:"labelMap,omitempty"`
|
||||||
|
|
||||||
defaultRuleTpl *template.Template
|
defaultRuleTpl *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LabelMapItem struct {
|
||||||
|
From string `description:"Shorthand label." json:"from,omitempty" toml:"from,omitempty" yaml:"from,omitempty"`
|
||||||
|
To string `description:"Full label with templates." json:"to,omitempty" toml:"to,omitempty" yaml:"to,omitempty"`
|
||||||
|
Value *string `description:"Optional override; used instead of user input if set." json:"value,omitempty" toml:"value,omitempty" yaml:"value,omitempty"`
|
||||||
|
toTpl *template.Template
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func inspectContainers(ctx context.Context, dockerClient client.ContainerAPIClient, containerID string) dockerData {
|
func inspectContainers(ctx context.Context, dockerClient client.ContainerAPIClient, containerID string) dockerData {
|
||||||
containerInspected, err := dockerClient.ContainerInspect(ctx, containerID)
|
containerInspected, err := dockerClient.ContainerInspect(ctx, containerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue