Merge branch 'v1.7' into master
This commit is contained in:
commit
4055654e9b
63 changed files with 2687 additions and 852 deletions
|
@ -62,6 +62,8 @@ type Provider struct {
|
|||
clientMutex sync.Mutex
|
||||
configFromListenerChan chan types.Configuration
|
||||
pool *safe.Pool
|
||||
resolvingDomains map[string]struct{}
|
||||
resolvingDomainsMutex sync.RWMutex
|
||||
}
|
||||
|
||||
// Certificate is a struct which contains all data needed from an ACME certificate
|
||||
|
@ -144,6 +146,9 @@ func (p *Provider) Init(_ types.Constraints) error {
|
|||
return fmt.Errorf("unable to get ACME certificates : %v", err)
|
||||
}
|
||||
|
||||
// Init the currently resolved domain map
|
||||
p.resolvingDomains = make(map[string]struct{})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -309,6 +314,12 @@ func (p *Provider) initAccount() (*Account, error) {
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Set the KeyType if not already defined in the account
|
||||
if len(p.account.KeyType) == 0 {
|
||||
p.account.KeyType = GetKeyType(p.KeyType)
|
||||
}
|
||||
|
||||
return p.account, nil
|
||||
}
|
||||
|
||||
|
@ -367,6 +378,9 @@ func (p *Provider) resolveCertificate(domain types.Domain, domainFromConfigurati
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
p.addResolvingDomains(uncheckedDomains)
|
||||
defer p.removeResolvingDomains(uncheckedDomains)
|
||||
|
||||
log.Debugf("Loading ACME certificates %+v...", uncheckedDomains)
|
||||
|
||||
client, err := p.getClient()
|
||||
|
@ -404,6 +418,24 @@ func (p *Provider) resolveCertificate(domain types.Domain, domainFromConfigurati
|
|||
return certificate, nil
|
||||
}
|
||||
|
||||
func (p *Provider) removeResolvingDomains(resolvingDomains []string) {
|
||||
p.resolvingDomainsMutex.Lock()
|
||||
defer p.resolvingDomainsMutex.Unlock()
|
||||
|
||||
for _, domain := range resolvingDomains {
|
||||
delete(p.resolvingDomains, domain)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Provider) addResolvingDomains(resolvingDomains []string) {
|
||||
p.resolvingDomainsMutex.Lock()
|
||||
defer p.resolvingDomainsMutex.Unlock()
|
||||
|
||||
for _, domain := range resolvingDomains {
|
||||
p.resolvingDomains[domain] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Provider) useCertificateWithRetry(domains []string) bool {
|
||||
// Check if we can use the retry mechanism only if we use the DNS Challenge and if is there are at least 2 domains to check
|
||||
if p.DNSChallenge != nil && len(domains) > 1 {
|
||||
|
@ -630,6 +662,9 @@ func (p *Provider) renewCertificates() {
|
|||
// Get provided certificate which check a domains list (Main and SANs)
|
||||
// from static and dynamic provided certificates
|
||||
func (p *Provider) getUncheckedDomains(domainsToCheck []string, checkConfigurationDomains bool) []string {
|
||||
p.resolvingDomainsMutex.RLock()
|
||||
defer p.resolvingDomainsMutex.RUnlock()
|
||||
|
||||
log.Debugf("Looking for provided certificate(s) to validate %q...", domainsToCheck)
|
||||
|
||||
allDomains := p.certificateStore.GetAllDomains()
|
||||
|
@ -639,6 +674,11 @@ func (p *Provider) getUncheckedDomains(domainsToCheck []string, checkConfigurati
|
|||
allDomains = append(allDomains, strings.Join(certificate.Domain.ToStrArray(), ","))
|
||||
}
|
||||
|
||||
// Get currently resolved domains
|
||||
for domain := range p.resolvingDomains {
|
||||
allDomains = append(allDomains, domain)
|
||||
}
|
||||
|
||||
// Get Configuration Domains
|
||||
if checkConfigurationDomains {
|
||||
for i := 0; i < len(p.Domains); i++ {
|
||||
|
@ -658,7 +698,7 @@ func searchUncheckedDomains(domainsToCheck []string, existentDomains []string) [
|
|||
}
|
||||
|
||||
if len(uncheckedDomains) == 0 {
|
||||
log.Debugf("No ACME certificate to generate for domains %q.", domainsToCheck)
|
||||
log.Debugf("No ACME certificate generation required for domains %q.", domainsToCheck)
|
||||
} else {
|
||||
log.Debugf("Domains %q need ACME certificates generation for domains %q.", domainsToCheck, strings.Join(uncheckedDomains, ","))
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
traefiktls "github.com/containous/traefik/tls"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/xenolf/lego/acme"
|
||||
)
|
||||
|
||||
func TestGetUncheckedCertificates(t *testing.T) {
|
||||
|
@ -27,6 +28,7 @@ func TestGetUncheckedCertificates(t *testing.T) {
|
|||
desc string
|
||||
dynamicCerts *safe.Safe
|
||||
staticCerts *safe.Safe
|
||||
resolvingDomains map[string]struct{}
|
||||
acmeCertificates []*Certificate
|
||||
domains []string
|
||||
expectedDomains []string
|
||||
|
@ -139,6 +141,40 @@ func TestGetUncheckedCertificates(t *testing.T) {
|
|||
},
|
||||
expectedDomains: []string{"traefik.wtf"},
|
||||
},
|
||||
{
|
||||
desc: "all domains already managed by ACME",
|
||||
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
|
||||
resolvingDomains: map[string]struct{}{
|
||||
"traefik.wtf": {},
|
||||
"foo.traefik.wtf": {},
|
||||
},
|
||||
expectedDomains: []string{},
|
||||
},
|
||||
{
|
||||
desc: "one domain already managed by ACME",
|
||||
domains: []string{"traefik.wtf", "foo.traefik.wtf"},
|
||||
resolvingDomains: map[string]struct{}{
|
||||
"traefik.wtf": {},
|
||||
},
|
||||
expectedDomains: []string{"foo.traefik.wtf"},
|
||||
},
|
||||
{
|
||||
desc: "wildcard domain already managed by ACME checks the domains",
|
||||
domains: []string{"bar.traefik.wtf", "foo.traefik.wtf"},
|
||||
resolvingDomains: map[string]struct{}{
|
||||
"*.traefik.wtf": {},
|
||||
},
|
||||
expectedDomains: []string{},
|
||||
},
|
||||
{
|
||||
desc: "wildcard domain already managed by ACME checks domains and another domain checks one other domain, one domain still unchecked",
|
||||
domains: []string{"traefik.wtf", "bar.traefik.wtf", "foo.traefik.wtf", "acme.wtf"},
|
||||
resolvingDomains: map[string]struct{}{
|
||||
"*.traefik.wtf": {},
|
||||
"traefik.wtf": {},
|
||||
},
|
||||
expectedDomains: []string{"acme.wtf"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
@ -146,12 +182,17 @@ func TestGetUncheckedCertificates(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if test.resolvingDomains == nil {
|
||||
test.resolvingDomains = make(map[string]struct{})
|
||||
}
|
||||
|
||||
acmeProvider := Provider{
|
||||
certificateStore: &traefiktls.CertificateStore{
|
||||
DynamicCerts: test.dynamicCerts,
|
||||
StaticCerts: test.staticCerts,
|
||||
},
|
||||
certificates: test.acmeCertificates,
|
||||
certificates: test.acmeCertificates,
|
||||
resolvingDomains: test.resolvingDomains,
|
||||
}
|
||||
|
||||
domains := acmeProvider.getUncheckedDomains(test.domains, false)
|
||||
|
@ -562,3 +603,82 @@ func TestUseBackOffToObtainCertificate(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitAccount(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
account *Account
|
||||
email string
|
||||
keyType string
|
||||
expectedAccount *Account
|
||||
}{
|
||||
{
|
||||
desc: "Existing account with all information",
|
||||
account: &Account{
|
||||
Email: "foo@foo.net",
|
||||
KeyType: acme.EC256,
|
||||
},
|
||||
expectedAccount: &Account{
|
||||
Email: "foo@foo.net",
|
||||
KeyType: acme.EC256,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Account nil",
|
||||
email: "foo@foo.net",
|
||||
keyType: "EC256",
|
||||
expectedAccount: &Account{
|
||||
Email: "foo@foo.net",
|
||||
KeyType: acme.EC256,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Existing account with no email",
|
||||
account: &Account{
|
||||
KeyType: acme.RSA4096,
|
||||
},
|
||||
email: "foo@foo.net",
|
||||
keyType: "EC256",
|
||||
expectedAccount: &Account{
|
||||
Email: "foo@foo.net",
|
||||
KeyType: acme.EC256,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Existing account with no key type",
|
||||
account: &Account{
|
||||
Email: "foo@foo.net",
|
||||
},
|
||||
email: "bar@foo.net",
|
||||
keyType: "EC256",
|
||||
expectedAccount: &Account{
|
||||
Email: "foo@foo.net",
|
||||
KeyType: acme.EC256,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Existing account and provider with no key type",
|
||||
account: &Account{
|
||||
Email: "foo@foo.net",
|
||||
},
|
||||
email: "bar@foo.net",
|
||||
expectedAccount: &Account{
|
||||
Email: "foo@foo.net",
|
||||
KeyType: acme.RSA4096,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
acmeProvider := Provider{account: test.account, Configuration: &Configuration{Email: test.email, KeyType: test.keyType}}
|
||||
|
||||
actualAccount, err := acmeProvider.initAccount()
|
||||
assert.Nil(t, err, "Init account in error")
|
||||
assert.Equal(t, test.expectedAccount.Email, actualAccount.Email, "unexpected email account")
|
||||
assert.Equal(t, test.expectedAccount.KeyType, actualAccount.KeyType, "unexpected keyType account")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ func (p *Provider) buildConfiguration(catalog []catalogUpdate) *types.Configurat
|
|||
var services []*serviceUpdate
|
||||
for _, info := range catalog {
|
||||
if len(info.Nodes) > 0 {
|
||||
services = append(services, info.Service)
|
||||
services = append(services, p.generateFrontends(info.Service)...)
|
||||
allNodes = append(allNodes, info.Nodes...)
|
||||
}
|
||||
}
|
||||
|
@ -135,6 +135,9 @@ func (p *Provider) setupFrontEndRuleTemplate() {
|
|||
// Specific functions
|
||||
|
||||
func getServiceBackendName(service *serviceUpdate) string {
|
||||
if service.ParentServiceName != "" {
|
||||
return strings.ToLower(service.ParentServiceName)
|
||||
}
|
||||
return strings.ToLower(service.ServiceName)
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,80 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Should build config which contains three frontends and one backend",
|
||||
nodes: []catalogUpdate{
|
||||
{
|
||||
Service: &serviceUpdate{
|
||||
ServiceName: "test",
|
||||
Attributes: []string{
|
||||
"random.foo=bar",
|
||||
label.Prefix + "frontend.rule=Host:A",
|
||||
label.Prefix + "frontends.test1.rule=Host:B",
|
||||
label.Prefix + "frontends.test2.rule=Host:C",
|
||||
},
|
||||
},
|
||||
Nodes: []*api.ServiceEntry{
|
||||
{
|
||||
Service: &api.AgentService{
|
||||
Service: "test",
|
||||
Address: "127.0.0.1",
|
||||
Port: 80,
|
||||
Tags: []string{
|
||||
"random.foo=bar",
|
||||
},
|
||||
},
|
||||
Node: &api.Node{
|
||||
Node: "localhost",
|
||||
Address: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-test": {
|
||||
Backend: "backend-test",
|
||||
PassHostHeader: true,
|
||||
Routes: map[string]types.Route{
|
||||
"route-host-test": {
|
||||
Rule: "Host:A",
|
||||
},
|
||||
},
|
||||
EntryPoints: []string{},
|
||||
},
|
||||
"frontend-test-test1": {
|
||||
Backend: "backend-test",
|
||||
PassHostHeader: true,
|
||||
Routes: map[string]types.Route{
|
||||
"route-host-test-test1": {
|
||||
Rule: "Host:B",
|
||||
},
|
||||
},
|
||||
EntryPoints: []string{},
|
||||
},
|
||||
"frontend-test-test2": {
|
||||
Backend: "backend-test",
|
||||
PassHostHeader: true,
|
||||
Routes: map[string]types.Route{
|
||||
"route-host-test-test2": {
|
||||
Rule: "Host:C",
|
||||
},
|
||||
},
|
||||
EntryPoints: []string{},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-test": {
|
||||
Servers: map[string]types.Server{
|
||||
"test-0-O0Tnh-SwzY69M6SurTKP3wNKkzI": {
|
||||
URL: "http://127.0.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Should build config with a basic auth with a backward compatibility",
|
||||
nodes: []catalogUpdate{
|
||||
|
|
|
@ -50,9 +50,15 @@ type Service struct {
|
|||
}
|
||||
|
||||
type serviceUpdate struct {
|
||||
ServiceName string
|
||||
Attributes []string
|
||||
TraefikLabels map[string]string
|
||||
ServiceName string
|
||||
ParentServiceName string
|
||||
Attributes []string
|
||||
TraefikLabels map[string]string
|
||||
}
|
||||
|
||||
type frontendSegment struct {
|
||||
Name string
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
type catalogUpdate struct {
|
||||
|
@ -560,3 +566,52 @@ func (p *Provider) getConstraintTags(tags []string) []string {
|
|||
|
||||
return values
|
||||
}
|
||||
|
||||
func (p *Provider) generateFrontends(service *serviceUpdate) []*serviceUpdate {
|
||||
frontends := make([]*serviceUpdate, 0)
|
||||
// to support <prefix>.frontend.xxx
|
||||
frontends = append(frontends, &serviceUpdate{
|
||||
ServiceName: service.ServiceName,
|
||||
ParentServiceName: service.ServiceName,
|
||||
Attributes: service.Attributes,
|
||||
TraefikLabels: service.TraefikLabels,
|
||||
})
|
||||
|
||||
// loop over children of <prefix>.frontends.*
|
||||
for _, frontend := range getSegments(p.Prefix+".frontends", p.Prefix, service.TraefikLabels) {
|
||||
frontends = append(frontends, &serviceUpdate{
|
||||
ServiceName: service.ServiceName + "-" + frontend.Name,
|
||||
ParentServiceName: service.ServiceName,
|
||||
Attributes: service.Attributes,
|
||||
TraefikLabels: frontend.Labels,
|
||||
})
|
||||
}
|
||||
|
||||
return frontends
|
||||
}
|
||||
func getSegments(path string, prefix string, tree map[string]string) []*frontendSegment {
|
||||
segments := make([]*frontendSegment, 0)
|
||||
// find segment names
|
||||
segmentNames := make(map[string]bool)
|
||||
for key := range tree {
|
||||
if strings.HasPrefix(key, path+".") {
|
||||
segmentNames[strings.SplitN(strings.TrimPrefix(key, path+"."), ".", 2)[0]] = true
|
||||
}
|
||||
}
|
||||
|
||||
// get labels for each segment found
|
||||
for segment := range segmentNames {
|
||||
labels := make(map[string]string)
|
||||
for key, value := range tree {
|
||||
if strings.HasPrefix(key, path+"."+segment) {
|
||||
labels[prefix+".frontend"+strings.TrimPrefix(key, path+"."+segment)] = value
|
||||
}
|
||||
}
|
||||
segments = append(segments, &frontendSegment{
|
||||
Name: segment,
|
||||
Labels: labels,
|
||||
})
|
||||
}
|
||||
|
||||
return segments
|
||||
}
|
||||
|
|
80
provider/ecs/builder_test.go
Normal file
80
provider/ecs/builder_test.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
package ecs
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/service/ecs"
|
||||
)
|
||||
|
||||
func instance(ops ...func(*ecsInstance)) ecsInstance {
|
||||
e := &ecsInstance{
|
||||
containerDefinition: &ecs.ContainerDefinition{},
|
||||
}
|
||||
|
||||
for _, op := range ops {
|
||||
op(e)
|
||||
}
|
||||
|
||||
return *e
|
||||
}
|
||||
|
||||
func name(name string) func(*ecsInstance) {
|
||||
return func(e *ecsInstance) {
|
||||
e.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
func ID(ID string) func(*ecsInstance) {
|
||||
return func(e *ecsInstance) {
|
||||
e.ID = ID
|
||||
}
|
||||
}
|
||||
|
||||
func iMachine(opts ...func(*machine)) func(*ecsInstance) {
|
||||
return func(e *ecsInstance) {
|
||||
e.machine = &machine{}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(e.machine)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mState(state string) func(*machine) {
|
||||
return func(m *machine) {
|
||||
m.state = state
|
||||
}
|
||||
}
|
||||
|
||||
func mPrivateIP(ip string) func(*machine) {
|
||||
return func(m *machine) {
|
||||
m.privateIP = ip
|
||||
}
|
||||
}
|
||||
|
||||
func mPorts(opts ...func(*portMapping)) func(*machine) {
|
||||
return func(m *machine) {
|
||||
for _, opt := range opts {
|
||||
p := &portMapping{}
|
||||
opt(p)
|
||||
m.ports = append(m.ports, *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mPort(containerPort int32, hostPort int32) func(*portMapping) {
|
||||
return func(pm *portMapping) {
|
||||
pm.containerPort = int64(containerPort)
|
||||
pm.hostPort = int64(hostPort)
|
||||
}
|
||||
}
|
||||
|
||||
func labels(labels map[string]string) func(*ecsInstance) {
|
||||
return func(c *ecsInstance) {
|
||||
c.TraefikLabels = labels
|
||||
}
|
||||
}
|
||||
|
||||
func dockerLabels(labels map[string]*string) func(*ecsInstance) {
|
||||
return func(c *ecsInstance) {
|
||||
c.containerDefinition.DockerLabels = labels
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package ecs
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
@ -17,18 +19,6 @@ import (
|
|||
|
||||
// buildConfiguration fills the config template with the given instances
|
||||
func (p *Provider) buildConfiguration(instances []ecsInstance) (*types.Configuration, error) {
|
||||
services := make(map[string][]ecsInstance)
|
||||
for _, instance := range instances {
|
||||
backendName := getBackendName(instance)
|
||||
if p.filterInstance(instance) {
|
||||
if serviceInstances, ok := services[backendName]; ok {
|
||||
services[backendName] = append(serviceInstances, instance)
|
||||
} else {
|
||||
services[backendName] = []ecsInstance{instance}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ecsFuncMap = template.FuncMap{
|
||||
// Backend functions
|
||||
"getHost": getHost,
|
||||
|
@ -43,6 +33,7 @@ func (p *Provider) buildConfiguration(instances []ecsInstance) (*types.Configura
|
|||
// Frontend functions
|
||||
"filterFrontends": filterFrontends,
|
||||
"getFrontendRule": p.getFrontendRule,
|
||||
"getFrontendName": p.getFrontendName,
|
||||
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
||||
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
||||
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
||||
|
@ -56,6 +47,25 @@ func (p *Provider) buildConfiguration(instances []ecsInstance) (*types.Configura
|
|||
"getWhiteList": label.GetWhiteList,
|
||||
}
|
||||
|
||||
services := make(map[string][]ecsInstance)
|
||||
for _, instance := range instances {
|
||||
segmentProperties := label.ExtractTraefikLabels(instance.TraefikLabels)
|
||||
|
||||
for segmentName, labels := range segmentProperties {
|
||||
instance.SegmentLabels = labels
|
||||
instance.SegmentName = segmentName
|
||||
|
||||
backendName := getBackendName(instance)
|
||||
if p.filterInstance(instance) {
|
||||
if serviceInstances, ok := services[backendName]; ok {
|
||||
services[backendName] = append(serviceInstances, instance)
|
||||
} else {
|
||||
services[backendName] = []ecsInstance{instance}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p.GetConfiguration("templates/ecs.tmpl", ecsFuncMap, struct {
|
||||
Services map[string][]ecsInstance
|
||||
}{
|
||||
|
@ -101,25 +111,61 @@ func (p *Provider) filterInstance(i ecsInstance) bool {
|
|||
}
|
||||
|
||||
func getBackendName(i ecsInstance) string {
|
||||
if value := label.GetStringValue(i.TraefikLabels, label.TraefikBackend, ""); len(value) > 0 {
|
||||
return value
|
||||
if len(i.SegmentName) > 0 {
|
||||
return getSegmentBackendName(i)
|
||||
}
|
||||
return i.Name
|
||||
|
||||
return getDefaultBackendName(i)
|
||||
}
|
||||
|
||||
func getSegmentBackendName(i ecsInstance) string {
|
||||
if value := label.GetStringValue(i.SegmentLabels, label.TraefikBackend, ""); len(value) > 0 {
|
||||
return provider.Normalize(i.Name + "-" + value)
|
||||
}
|
||||
|
||||
return provider.Normalize(i.Name + "-" + i.SegmentName)
|
||||
}
|
||||
|
||||
func getDefaultBackendName(i ecsInstance) string {
|
||||
if value := label.GetStringValue(i.SegmentLabels, label.TraefikBackend, ""); len(value) != 0 {
|
||||
return provider.Normalize(value)
|
||||
}
|
||||
|
||||
return provider.Normalize(i.Name)
|
||||
}
|
||||
|
||||
func (p *Provider) getFrontendRule(i ecsInstance) string {
|
||||
domain := label.GetStringValue(i.TraefikLabels, label.TraefikDomain, p.Domain)
|
||||
if value := label.GetStringValue(i.SegmentLabels, label.TraefikFrontendRule, ""); len(value) != 0 {
|
||||
return value
|
||||
}
|
||||
|
||||
domain := label.GetStringValue(i.SegmentLabels, label.TraefikDomain, p.Domain)
|
||||
defaultRule := "Host:" + strings.ToLower(strings.Replace(i.Name, "_", "-", -1)) + "." + domain
|
||||
|
||||
return label.GetStringValue(i.TraefikLabels, label.TraefikFrontendRule, defaultRule)
|
||||
}
|
||||
|
||||
func (p *Provider) getFrontendName(instance ecsInstance) string {
|
||||
name := getBackendName(instance)
|
||||
if len(instance.SegmentName) > 0 {
|
||||
name = instance.SegmentName + "-" + name
|
||||
}
|
||||
|
||||
return provider.Normalize(name)
|
||||
}
|
||||
|
||||
func getHost(i ecsInstance) string {
|
||||
return i.machine.privateIP
|
||||
}
|
||||
|
||||
func getPort(i ecsInstance) string {
|
||||
if value := label.GetStringValue(i.TraefikLabels, label.TraefikPort, ""); len(value) > 0 {
|
||||
value := label.GetStringValue(i.SegmentLabels, label.TraefikPort, "")
|
||||
|
||||
if len(value) == 0 {
|
||||
value = label.GetStringValue(i.TraefikLabels, label.TraefikPort, "")
|
||||
}
|
||||
|
||||
if len(value) > 0 {
|
||||
port, err := strconv.ParseInt(value, 10, 64)
|
||||
if err == nil {
|
||||
for _, mapping := range i.machine.ports {
|
||||
|
@ -138,6 +184,10 @@ func filterFrontends(instances []ecsInstance) []ecsInstance {
|
|||
|
||||
return fun.Filter(func(i ecsInstance) bool {
|
||||
backendName := getBackendName(i)
|
||||
if len(i.SegmentName) > 0 {
|
||||
backendName = backendName + "-" + i.SegmentName
|
||||
}
|
||||
|
||||
_, found := byName[backendName]
|
||||
if !found {
|
||||
byName[backendName] = struct{}{}
|
||||
|
@ -154,14 +204,21 @@ func getServers(instances []ecsInstance) map[string]types.Server {
|
|||
servers = make(map[string]types.Server)
|
||||
}
|
||||
|
||||
protocol := label.GetStringValue(instance.TraefikLabels, label.TraefikProtocol, label.DefaultProtocol)
|
||||
protocol := label.GetStringValue(instance.SegmentLabels, label.TraefikProtocol, label.DefaultProtocol)
|
||||
host := getHost(instance)
|
||||
port := getPort(instance)
|
||||
|
||||
serverName := provider.Normalize(fmt.Sprintf("server-%s-%s", instance.Name, instance.ID))
|
||||
serverURL := fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(host, port))
|
||||
serverName := getServerName(instance, serverURL)
|
||||
|
||||
if _, exist := servers[serverName]; exist {
|
||||
log.Debugf("Skipping server %q with the same URL.", serverName)
|
||||
continue
|
||||
}
|
||||
|
||||
servers[serverName] = types.Server{
|
||||
URL: fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(host, port)),
|
||||
Weight: label.GetIntValue(instance.TraefikLabels, label.TraefikWeight, label.DefaultWeight),
|
||||
URL: serverURL,
|
||||
Weight: label.GetIntValue(instance.SegmentLabels, label.TraefikWeight, label.DefaultWeight),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,3 +228,18 @@ func getServers(instances []ecsInstance) map[string]types.Server {
|
|||
func isEnabled(i ecsInstance, exposedByDefault bool) bool {
|
||||
return label.GetBoolValue(i.TraefikLabels, label.TraefikEnable, exposedByDefault)
|
||||
}
|
||||
|
||||
func getServerName(instance ecsInstance, url string) string {
|
||||
hash := md5.New()
|
||||
_, err := hash.Write([]byte(url))
|
||||
if err != nil {
|
||||
// Impossible case
|
||||
log.Errorf("Fail to hash server URL %q", url)
|
||||
}
|
||||
|
||||
if len(instance.SegmentName) > 0 {
|
||||
return provider.Normalize(fmt.Sprintf("server-%s-%s-%s", instance.Name, instance.ID, hex.EncodeToString(hash.Sum(nil))))
|
||||
}
|
||||
|
||||
return provider.Normalize(fmt.Sprintf("server-%s-%s", instance.Name, instance.ID))
|
||||
}
|
||||
|
|
852
provider/ecs/config_segment_test.go
Normal file
852
provider/ecs/config_segment_test.go
Normal file
|
@ -0,0 +1,852 @@
|
|||
package ecs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/containous/flaeg/parse"
|
||||
"github.com/containous/traefik/provider/label"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSegmentBuildConfiguration(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
instanceInfo []ecsInstance
|
||||
expectedFrontends map[string]*types.Frontend
|
||||
expectedBackends map[string]*types.Backend
|
||||
}{
|
||||
{
|
||||
desc: "when no container",
|
||||
instanceInfo: []ecsInstance{},
|
||||
expectedFrontends: map[string]*types.Frontend{},
|
||||
expectedBackends: map[string]*types.Backend{},
|
||||
},
|
||||
{
|
||||
desc: "simple configuration",
|
||||
instanceInfo: []ecsInstance{
|
||||
instance(
|
||||
ID("123456789abc"),
|
||||
name("foo"),
|
||||
labels(map[string]string{
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.frontend.entryPoints": "http,https",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 2503),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-sauternes-foo-sauternes": {
|
||||
Backend: "backend-foo-sauternes",
|
||||
PassHostHeader: true,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-sauternes-foo-sauternes": {
|
||||
Rule: "Host:foo.ecs.localhost",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-foo-sauternes": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-foo-123456789abc-863563a2e23c95502862016417ee95ea": {
|
||||
URL: "http://127.0.0.1:2503",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "auth basic",
|
||||
instanceInfo: []ecsInstance{
|
||||
instance(
|
||||
ID("123456789abc"),
|
||||
name("foo"),
|
||||
labels(map[string]string{
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.frontend.entryPoints": "http,https",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthHeaderField: "X-WebAuth-User",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicRemoveHeader: "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 2503),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-sauternes-foo-sauternes": {
|
||||
Backend: "backend-foo-sauternes",
|
||||
PassHostHeader: true,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-sauternes-foo-sauternes": {
|
||||
Rule: "Host:foo.ecs.localhost",
|
||||
},
|
||||
},
|
||||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-foo-sauternes": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-foo-123456789abc-863563a2e23c95502862016417ee95ea": {
|
||||
URL: "http://127.0.0.1:2503",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "auth basic backward compatibility",
|
||||
instanceInfo: []ecsInstance{
|
||||
instance(
|
||||
ID("123456789abc"),
|
||||
name("foo"),
|
||||
labels(map[string]string{
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.frontend.entryPoints": "http,https",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 2503),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-sauternes-foo-sauternes": {
|
||||
Backend: "backend-foo-sauternes",
|
||||
PassHostHeader: true,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-sauternes-foo-sauternes": {
|
||||
Rule: "Host:foo.ecs.localhost",
|
||||
},
|
||||
},
|
||||
Auth: &types.Auth{
|
||||
Basic: &types.Basic{
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-foo-sauternes": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-foo-123456789abc-863563a2e23c95502862016417ee95ea": {
|
||||
URL: "http://127.0.0.1:2503",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "auth digest",
|
||||
instanceInfo: []ecsInstance{
|
||||
instance(
|
||||
ID("123456789abc"),
|
||||
name("foo"),
|
||||
labels(map[string]string{
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.frontend.entryPoints": "http,https",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthHeaderField: "X-WebAuth-User",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestRemoveHeader: "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 2503),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-sauternes-foo-sauternes": {
|
||||
Backend: "backend-foo-sauternes",
|
||||
PassHostHeader: true,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-sauternes-foo-sauternes": {
|
||||
Rule: "Host:foo.ecs.localhost",
|
||||
},
|
||||
},
|
||||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-foo-sauternes": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-foo-123456789abc-863563a2e23c95502862016417ee95ea": {
|
||||
URL: "http://127.0.0.1:2503",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "auth forward",
|
||||
instanceInfo: []ecsInstance{
|
||||
instance(
|
||||
ID("123456789abc"),
|
||||
name("foo"),
|
||||
labels(map[string]string{
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.frontend.entryPoints": "http,https",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthHeaderField: "X-WebAuth-User",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardAddress: "auth.server",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTrustForwardHeader: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSCa: "ca.crt",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSCaOptional: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSCert: "server.crt",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSKey: "server.key",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSInsecureSkipVerify: "true",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 2503),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-sauternes-foo-sauternes": {
|
||||
Backend: "backend-foo-sauternes",
|
||||
PassHostHeader: true,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-sauternes-foo-sauternes": {
|
||||
Rule: "Host:foo.ecs.localhost",
|
||||
},
|
||||
},
|
||||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Forward: &types.Forward{
|
||||
Address: "auth.server",
|
||||
TrustForwardHeader: true,
|
||||
TLS: &types.ClientTLS{
|
||||
CA: "ca.crt",
|
||||
CAOptional: true,
|
||||
Cert: "server.crt",
|
||||
Key: "server.key",
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-foo-sauternes": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-foo-123456789abc-863563a2e23c95502862016417ee95ea": {
|
||||
URL: "http://127.0.0.1:2503",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when all labels are set",
|
||||
instanceInfo: []ecsInstance{
|
||||
instance(
|
||||
ID("123456789abc"),
|
||||
name("foo"),
|
||||
labels(map[string]string{
|
||||
label.Prefix + "sauternes." + label.SuffixPort: "666",
|
||||
label.Prefix + "sauternes." + label.SuffixProtocol: "https",
|
||||
label.Prefix + "sauternes." + label.SuffixWeight: "12",
|
||||
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicRemoveHeader: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestRemoveHeader: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardAddress: "auth.server",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTrustForwardHeader: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSCa: "ca.crt",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSCaOptional: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSCert: "server.crt",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSKey: "server.key",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSInsecureSkipVerify: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthHeaderField: "X-WebAuth-User",
|
||||
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendEntryPoints: "http,https",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendPassHostHeader: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendPassTLSCert: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendPriority: "666",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendRedirectEntryPoint: "https",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendRedirectRegex: "nope",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendRedirectReplacement: "nope",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendRedirectPermanent: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendWhiteListSourceRange: "10.10.10.10",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendWhiteListIPStrategyExcludedIPS: "10.10.10.10,10.10.10.11",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendWhiteListIPStrategyDepth: "5",
|
||||
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendRequestHeaders: "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendResponseHeaders: "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersSSLProxyHeaders: "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersAllowedHosts: "foo,bar,bor",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersHostsProxyHeaders: "foo,bar,bor",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersSSLHost: "foo",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersCustomFrameOptionsValue: "foo",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersContentSecurityPolicy: "foo",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersPublicKey: "foo",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersReferrerPolicy: "foo",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersCustomBrowserXSSValue: "foo",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersSTSSeconds: "666",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersSSLForceHost: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersSSLRedirect: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersSSLTemporaryRedirect: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersSTSIncludeSubdomains: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersSTSPreload: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersForceSTSHeader: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersFrameDeny: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersContentTypeNosniff: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersBrowserXSSFilter: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendHeadersIsDevelopment: "true",
|
||||
|
||||
label.Prefix + "sauternes." + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: "404",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageBackend: "foobar",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageQuery: "foo_query",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageStatus: "500,600",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageBackend: "foobar",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageQuery: "bar_query",
|
||||
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendRateLimitExtractorFunc: "client.ip",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitPeriod: "6",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitAverage: "12",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitBurst: "18",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitPeriod: "3",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitAverage: "6",
|
||||
label.Prefix + "sauternes." + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitBurst: "9",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 666),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-sauternes-foo-sauternes": {
|
||||
Backend: "backend-foo-sauternes",
|
||||
EntryPoints: []string{
|
||||
"http",
|
||||
"https",
|
||||
},
|
||||
PassHostHeader: true,
|
||||
PassTLSCert: true,
|
||||
Priority: 666,
|
||||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
},
|
||||
},
|
||||
WhiteList: &types.WhiteList{
|
||||
SourceRange: []string{"10.10.10.10"},
|
||||
IPStrategy: &types.IPStrategy{
|
||||
Depth: 5,
|
||||
ExcludedIPs: []string{"10.10.10.10", "10.10.10.11"},
|
||||
},
|
||||
},
|
||||
Headers: &types.Headers{
|
||||
CustomRequestHeaders: map[string]string{
|
||||
"Access-Control-Allow-Methods": "POST,GET,OPTIONS",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
CustomResponseHeaders: map[string]string{
|
||||
"Access-Control-Allow-Methods": "POST,GET,OPTIONS",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
AllowedHosts: []string{
|
||||
"foo",
|
||||
"bar",
|
||||
"bor",
|
||||
},
|
||||
HostsProxyHeaders: []string{
|
||||
"foo",
|
||||
"bar",
|
||||
"bor",
|
||||
},
|
||||
SSLRedirect: true,
|
||||
SSLTemporaryRedirect: true,
|
||||
SSLForceHost: true,
|
||||
SSLHost: "foo",
|
||||
SSLProxyHeaders: map[string]string{
|
||||
"Access-Control-Allow-Methods": "POST,GET,OPTIONS",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
STSSeconds: 666,
|
||||
STSIncludeSubdomains: true,
|
||||
STSPreload: true,
|
||||
ForceSTSHeader: true,
|
||||
FrameDeny: true,
|
||||
CustomFrameOptionsValue: "foo",
|
||||
ContentTypeNosniff: true,
|
||||
BrowserXSSFilter: true,
|
||||
CustomBrowserXSSValue: "foo",
|
||||
ContentSecurityPolicy: "foo",
|
||||
PublicKey: "foo",
|
||||
ReferrerPolicy: "foo",
|
||||
IsDevelopment: true,
|
||||
},
|
||||
Errors: map[string]*types.ErrorPage{
|
||||
"foo": {
|
||||
Status: []string{"404"},
|
||||
Query: "foo_query",
|
||||
Backend: "backend-foobar",
|
||||
},
|
||||
"bar": {
|
||||
Status: []string{"500", "600"},
|
||||
Query: "bar_query",
|
||||
Backend: "backend-foobar",
|
||||
},
|
||||
},
|
||||
RateLimit: &types.RateLimit{
|
||||
ExtractorFunc: "client.ip",
|
||||
RateSet: map[string]*types.Rate{
|
||||
"foo": {
|
||||
Period: parse.Duration(6 * time.Second),
|
||||
Average: 12,
|
||||
Burst: 18,
|
||||
},
|
||||
"bar": {
|
||||
Period: parse.Duration(3 * time.Second),
|
||||
Average: 6,
|
||||
Burst: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
Regex: "",
|
||||
Replacement: "",
|
||||
Permanent: true,
|
||||
},
|
||||
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-sauternes-foo-sauternes": {
|
||||
Rule: "Host:foo.ecs.localhost",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-foo-sauternes": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-foo-123456789abc-7f6444e0dff3330c8b0ad2bbbd383b0f": {
|
||||
URL: "https://127.0.0.1:666",
|
||||
Weight: 12,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "several containers",
|
||||
instanceInfo: []ecsInstance{
|
||||
instance(
|
||||
ID("123456789abc"),
|
||||
name("test1"),
|
||||
labels(map[string]string{
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.protocol": "https",
|
||||
"traefik.sauternes.weight": "80",
|
||||
"traefik.sauternes.backend": "foobar",
|
||||
"traefik.sauternes.frontend.passHostHeader": "false",
|
||||
"traefik.sauternes.frontend.rule": "Path:/mypath",
|
||||
"traefik.sauternes.frontend.priority": "5000",
|
||||
"traefik.sauternes.frontend.entryPoints": "http,https,ws",
|
||||
"traefik.sauternes.frontend.auth.basic": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
"traefik.sauternes.frontend.redirect.entryPoint": "https",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 2503),
|
||||
),
|
||||
),
|
||||
),
|
||||
instance(
|
||||
ID("abc987654321"),
|
||||
name("test2"),
|
||||
labels(map[string]string{
|
||||
"traefik.anothersauternes.port": "8079",
|
||||
"traefik.anothersauternes.weight": "33",
|
||||
"traefik.anothersauternes.frontend.rule": "Path:/anotherpath",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.2"),
|
||||
mPorts(
|
||||
mPort(80, 8079),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-sauternes-test1-foobar": {
|
||||
Backend: "backend-test1-foobar",
|
||||
PassHostHeader: false,
|
||||
Priority: 5000,
|
||||
EntryPoints: []string{"http", "https", "ws"},
|
||||
Auth: &types.Auth{
|
||||
Basic: &types.Basic{
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
},
|
||||
},
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-sauternes-test1-foobar": {
|
||||
Rule: "Path:/mypath",
|
||||
},
|
||||
},
|
||||
},
|
||||
"frontend-anothersauternes-test2-anothersauternes": {
|
||||
Backend: "backend-test2-anothersauternes",
|
||||
PassHostHeader: true,
|
||||
EntryPoints: []string{},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-anothersauternes-test2-anothersauternes": {
|
||||
Rule: "Path:/anotherpath",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-test1-foobar": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-test1-123456789abc-79533a101142718f0fdf84c42593c41e": {
|
||||
URL: "https://127.0.0.1:2503",
|
||||
Weight: 80,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
"backend-test2-anothersauternes": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-test2-abc987654321-045e3e4aa5a744a325c099b803700a93": {
|
||||
URL: "http://127.0.0.2:8079",
|
||||
Weight: 33,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "several segments with the same backend name and same port",
|
||||
instanceInfo: []ecsInstance{
|
||||
instance(
|
||||
ID("123456789abc"),
|
||||
name("test1"),
|
||||
labels(map[string]string{
|
||||
"traefik.port": "2503",
|
||||
"traefik.protocol": "https",
|
||||
"traefik.weight": "80",
|
||||
"traefik.frontend.entryPoints": "http,https",
|
||||
"traefik.frontend.redirect.entryPoint": "https",
|
||||
|
||||
"traefik.sauternes.backend": "foobar",
|
||||
"traefik.sauternes.frontend.rule": "Path:/sauternes",
|
||||
"traefik.sauternes.frontend.priority": "5000",
|
||||
|
||||
"traefik.arbois.backend": "foobar",
|
||||
"traefik.arbois.frontend.rule": "Path:/arbois",
|
||||
"traefik.arbois.frontend.priority": "3000",
|
||||
}),
|
||||
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 2503),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-sauternes-test1-foobar": {
|
||||
Backend: "backend-test1-foobar",
|
||||
PassHostHeader: true,
|
||||
Priority: 5000,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-sauternes-test1-foobar": {
|
||||
Rule: "Path:/sauternes",
|
||||
},
|
||||
},
|
||||
},
|
||||
"frontend-arbois-test1-foobar": {
|
||||
Backend: "backend-test1-foobar",
|
||||
PassHostHeader: true,
|
||||
Priority: 3000,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-arbois-test1-foobar": {
|
||||
Rule: "Path:/arbois",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-test1-foobar": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-test1-123456789abc-79533a101142718f0fdf84c42593c41e": {
|
||||
URL: "https://127.0.0.1:2503",
|
||||
Weight: 80,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "several segments with the same backend name and different port (wrong behavior)",
|
||||
instanceInfo: []ecsInstance{
|
||||
instance(
|
||||
ID("123456789abc"),
|
||||
name("test1"),
|
||||
labels(map[string]string{
|
||||
"traefik.protocol": "https",
|
||||
"traefik.frontend.entryPoints": "http,https",
|
||||
"traefik.frontend.redirect.entryPoint": "https",
|
||||
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.weight": "80",
|
||||
"traefik.sauternes.backend": "foobar",
|
||||
"traefik.sauternes.frontend.rule": "Path:/sauternes",
|
||||
"traefik.sauternes.frontend.priority": "5000",
|
||||
|
||||
"traefik.arbois.port": "2504",
|
||||
"traefik.arbois.weight": "90",
|
||||
"traefik.arbois.backend": "foobar",
|
||||
"traefik.arbois.frontend.rule": "Path:/arbois",
|
||||
"traefik.arbois.frontend.priority": "3000",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 2503),
|
||||
mPort(80, 2504),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-sauternes-test1-foobar": {
|
||||
Backend: "backend-test1-foobar",
|
||||
PassHostHeader: true,
|
||||
Priority: 5000,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-sauternes-test1-foobar": {
|
||||
Rule: "Path:/sauternes",
|
||||
},
|
||||
},
|
||||
},
|
||||
"frontend-arbois-test1-foobar": {
|
||||
Backend: "backend-test1-foobar",
|
||||
PassHostHeader: true,
|
||||
Priority: 3000,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-arbois-test1-foobar": {
|
||||
Rule: "Path:/arbois",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-test1-foobar": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-test1-123456789abc-79533a101142718f0fdf84c42593c41e": {
|
||||
URL: "https://127.0.0.1:2503",
|
||||
Weight: 80,
|
||||
},
|
||||
"server-test1-123456789abc-315a41140f1bd825b066e39686c18482": {
|
||||
URL: "https://127.0.0.1:2504",
|
||||
Weight: 90,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "several segments with the same backend name and different port binding",
|
||||
instanceInfo: []ecsInstance{
|
||||
instance(
|
||||
ID("123456789abc"),
|
||||
name("test1"),
|
||||
labels(map[string]string{
|
||||
"traefik.protocol": "https",
|
||||
"traefik.frontend.entryPoints": "http,https",
|
||||
"traefik.frontend.redirect.entryPoint": "https",
|
||||
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.weight": "80",
|
||||
"traefik.sauternes.backend": "foobar",
|
||||
"traefik.sauternes.frontend.rule": "Path:/sauternes",
|
||||
"traefik.sauternes.frontend.priority": "5000",
|
||||
|
||||
"traefik.arbois.port": "8080",
|
||||
"traefik.arbois.weight": "90",
|
||||
"traefik.arbois.backend": "foobar",
|
||||
"traefik.arbois.frontend.rule": "Path:/arbois",
|
||||
"traefik.arbois.frontend.priority": "3000",
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("127.0.0.1"),
|
||||
mPorts(
|
||||
mPort(80, 2503),
|
||||
mPort(8080, 2504),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expectedFrontends: map[string]*types.Frontend{
|
||||
"frontend-sauternes-test1-foobar": {
|
||||
Backend: "backend-test1-foobar",
|
||||
PassHostHeader: true,
|
||||
Priority: 5000,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-sauternes-test1-foobar": {
|
||||
Rule: "Path:/sauternes",
|
||||
},
|
||||
},
|
||||
},
|
||||
"frontend-arbois-test1-foobar": {
|
||||
Backend: "backend-test1-foobar",
|
||||
PassHostHeader: true,
|
||||
Priority: 3000,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-arbois-test1-foobar": {
|
||||
Rule: "Path:/arbois",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedBackends: map[string]*types.Backend{
|
||||
"backend-test1-foobar": {
|
||||
Servers: map[string]types.Server{
|
||||
"server-test1-123456789abc-79533a101142718f0fdf84c42593c41e": {
|
||||
URL: "https://127.0.0.1:2503",
|
||||
Weight: 80,
|
||||
},
|
||||
"server-test1-123456789abc-315a41140f1bd825b066e39686c18482": {
|
||||
URL: "https://127.0.0.1:2504",
|
||||
Weight: 90,
|
||||
},
|
||||
},
|
||||
CircuitBreaker: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
provider := &Provider{
|
||||
Domain: "ecs.localhost",
|
||||
ExposedByDefault: true,
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actualConfig, err := provider.buildConfiguration(test.instanceInfo)
|
||||
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, actualConfig, "actualConfig")
|
||||
|
||||
assert.EqualValues(t, test.expectedBackends, actualConfig.Backends)
|
||||
assert.EqualValues(t, test.expectedFrontends, actualConfig.Frontends)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -23,18 +23,18 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
{
|
||||
desc: "config parsed successfully",
|
||||
instances: []ecsInstance{
|
||||
{
|
||||
Name: "instance",
|
||||
ID: "1",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{},
|
||||
},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
privateIP: "10.0.0.1",
|
||||
ports: []portMapping{{hostPort: 1337}},
|
||||
},
|
||||
},
|
||||
instance(
|
||||
name("instance"),
|
||||
ID("1"),
|
||||
dockerLabels(map[string]*string{}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("10.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 1337),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expected: &types.Configuration{
|
||||
Backends: map[string]*types.Backend{
|
||||
|
@ -63,20 +63,21 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
{
|
||||
desc: "config parsed successfully with health check labels",
|
||||
instances: []ecsInstance{
|
||||
{
|
||||
Name: "instance",
|
||||
ID: "1",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{
|
||||
label.TraefikBackendHealthCheckPath: aws.String("/health"),
|
||||
label.TraefikBackendHealthCheckInterval: aws.String("1s"),
|
||||
}},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
privateIP: "10.0.0.1",
|
||||
ports: []portMapping{{hostPort: 1337}},
|
||||
},
|
||||
},
|
||||
instance(
|
||||
name("instance"),
|
||||
ID("1"),
|
||||
dockerLabels(map[string]*string{
|
||||
label.TraefikBackendHealthCheckPath: aws.String("/health"),
|
||||
label.TraefikBackendHealthCheckInterval: aws.String("1s"),
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("10.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 1337),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expected: &types.Configuration{
|
||||
Backends: map[string]*types.Backend{
|
||||
|
@ -109,22 +110,23 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
{
|
||||
desc: "config parsed successfully with basic auth labels",
|
||||
instances: []ecsInstance{
|
||||
{
|
||||
Name: "instance",
|
||||
ID: "1",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{
|
||||
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthBasicUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
}},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
privateIP: "10.0.0.1",
|
||||
ports: []portMapping{{hostPort: 1337}},
|
||||
},
|
||||
},
|
||||
instance(
|
||||
name("instance"),
|
||||
ID("1"),
|
||||
dockerLabels(map[string]*string{
|
||||
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthBasicUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("10.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 1337),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expected: &types.Configuration{
|
||||
Backends: map[string]*types.Backend{
|
||||
|
@ -162,19 +164,20 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
{
|
||||
desc: "config parsed successfully with basic auth (backward compatibility) labels",
|
||||
instances: []ecsInstance{
|
||||
{
|
||||
Name: "instance",
|
||||
ID: "1",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{
|
||||
label.TraefikFrontendAuthBasic: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
}},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
privateIP: "10.0.0.1",
|
||||
ports: []portMapping{{hostPort: 1337}},
|
||||
},
|
||||
},
|
||||
instance(
|
||||
name("instance"),
|
||||
ID("1"),
|
||||
dockerLabels(map[string]*string{
|
||||
label.TraefikFrontendAuthBasic: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("10.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 1337),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expected: &types.Configuration{
|
||||
Backends: map[string]*types.Backend{
|
||||
|
@ -209,22 +212,23 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
{
|
||||
desc: "config parsed successfully with digest auth labels",
|
||||
instances: []ecsInstance{
|
||||
{
|
||||
Name: "instance",
|
||||
ID: "1",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthDigestUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthDigestUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
}},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
privateIP: "10.0.0.1",
|
||||
ports: []portMapping{{hostPort: 1337}},
|
||||
},
|
||||
},
|
||||
instance(
|
||||
name("instance"),
|
||||
ID("1"),
|
||||
dockerLabels(map[string]*string{
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthDigestUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthDigestUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("10.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 1337),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expected: &types.Configuration{
|
||||
Backends: map[string]*types.Backend{
|
||||
|
@ -262,25 +266,26 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
{
|
||||
desc: "config parsed successfully with forward auth labels",
|
||||
instances: []ecsInstance{
|
||||
{
|
||||
Name: "instance",
|
||||
ID: "1",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{
|
||||
label.TraefikFrontendAuthForwardAddress: aws.String("auth.server"),
|
||||
label.TraefikFrontendAuthForwardTrustForwardHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthForwardTLSCa: aws.String("ca.crt"),
|
||||
label.TraefikFrontendAuthForwardTLSCaOptional: aws.String("true"),
|
||||
label.TraefikFrontendAuthForwardTLSCert: aws.String("server.crt"),
|
||||
label.TraefikFrontendAuthForwardTLSKey: aws.String("server.key"),
|
||||
label.TraefikFrontendAuthForwardTLSInsecureSkipVerify: aws.String("true"), label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
}},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
privateIP: "10.0.0.1",
|
||||
ports: []portMapping{{hostPort: 1337}},
|
||||
},
|
||||
},
|
||||
instance(
|
||||
name("instance"),
|
||||
ID("1"),
|
||||
dockerLabels(map[string]*string{
|
||||
label.TraefikFrontendAuthForwardAddress: aws.String("auth.server"),
|
||||
label.TraefikFrontendAuthForwardTrustForwardHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthForwardTLSCa: aws.String("ca.crt"),
|
||||
label.TraefikFrontendAuthForwardTLSCaOptional: aws.String("true"),
|
||||
label.TraefikFrontendAuthForwardTLSCert: aws.String("server.crt"),
|
||||
label.TraefikFrontendAuthForwardTLSKey: aws.String("server.key"),
|
||||
label.TraefikFrontendAuthForwardTLSInsecureSkipVerify: aws.String("true"), label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("10.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 1337),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expected: &types.Configuration{
|
||||
Backends: map[string]*types.Backend{
|
||||
|
@ -323,108 +328,109 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
{
|
||||
desc: "when all labels are set",
|
||||
instances: []ecsInstance{
|
||||
{
|
||||
Name: "testing-instance",
|
||||
ID: "6",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{
|
||||
label.TraefikPort: aws.String("666"),
|
||||
label.TraefikProtocol: aws.String("https"),
|
||||
label.TraefikWeight: aws.String("12"),
|
||||
instance(
|
||||
name("testing-instance"),
|
||||
ID("6"),
|
||||
dockerLabels(map[string]*string{
|
||||
label.TraefikPort: aws.String("666"),
|
||||
label.TraefikProtocol: aws.String("https"),
|
||||
label.TraefikWeight: aws.String("12"),
|
||||
|
||||
label.TraefikBackend: aws.String("foobar"),
|
||||
label.TraefikBackend: aws.String("foobar"),
|
||||
|
||||
label.TraefikBackendCircuitBreakerExpression: aws.String("NetworkErrorRatio() > 0.5"),
|
||||
label.TraefikBackendHealthCheckScheme: aws.String("http"),
|
||||
label.TraefikBackendHealthCheckPath: aws.String("/health"),
|
||||
label.TraefikBackendHealthCheckPort: aws.String("880"),
|
||||
label.TraefikBackendHealthCheckInterval: aws.String("6"),
|
||||
label.TraefikBackendHealthCheckHostname: aws.String("foo.com"),
|
||||
label.TraefikBackendHealthCheckHeaders: aws.String("Foo:bar || Bar:foo"),
|
||||
label.TraefikBackendLoadBalancerMethod: aws.String("drr"),
|
||||
label.TraefikBackendLoadBalancerStickiness: aws.String("true"),
|
||||
label.TraefikBackendLoadBalancerStickinessCookieName: aws.String("chocolate"),
|
||||
label.TraefikBackendMaxConnAmount: aws.String("666"),
|
||||
label.TraefikBackendMaxConnExtractorFunc: aws.String("client.ip"),
|
||||
label.TraefikBackendBufferingMaxResponseBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemResponseBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingMaxRequestBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemRequestBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingRetryExpression: aws.String("IsNetworkError() && Attempts() <= 2"),
|
||||
label.TraefikBackendCircuitBreakerExpression: aws.String("NetworkErrorRatio() > 0.5"),
|
||||
label.TraefikBackendHealthCheckScheme: aws.String("http"),
|
||||
label.TraefikBackendHealthCheckPath: aws.String("/health"),
|
||||
label.TraefikBackendHealthCheckPort: aws.String("880"),
|
||||
label.TraefikBackendHealthCheckInterval: aws.String("6"),
|
||||
label.TraefikBackendHealthCheckHostname: aws.String("foo.com"),
|
||||
label.TraefikBackendHealthCheckHeaders: aws.String("Foo:bar || Bar:foo"),
|
||||
label.TraefikBackendLoadBalancerMethod: aws.String("drr"),
|
||||
label.TraefikBackendLoadBalancerStickiness: aws.String("true"),
|
||||
label.TraefikBackendLoadBalancerStickinessCookieName: aws.String("chocolate"),
|
||||
label.TraefikBackendMaxConnAmount: aws.String("666"),
|
||||
label.TraefikBackendMaxConnExtractorFunc: aws.String("client.ip"),
|
||||
label.TraefikBackendBufferingMaxResponseBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemResponseBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingMaxRequestBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemRequestBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingRetryExpression: aws.String("IsNetworkError() && Attempts() <= 2"),
|
||||
|
||||
label.TraefikFrontendAuthBasic: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthBasicUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthDigestUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthDigestUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthForwardAddress: aws.String("auth.server"),
|
||||
label.TraefikFrontendAuthForwardTrustForwardHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthForwardTLSCa: aws.String("ca.crt"),
|
||||
label.TraefikFrontendAuthForwardTLSCaOptional: aws.String("true"),
|
||||
label.TraefikFrontendAuthForwardTLSCert: aws.String("server.crt"),
|
||||
label.TraefikFrontendAuthForwardTLSKey: aws.String("server.key"),
|
||||
label.TraefikFrontendAuthForwardTLSInsecureSkipVerify: aws.String("true"),
|
||||
label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
label.TraefikFrontendAuthBasic: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthBasicUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthDigestUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthDigestUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthForwardAddress: aws.String("auth.server"),
|
||||
label.TraefikFrontendAuthForwardTrustForwardHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthForwardTLSCa: aws.String("ca.crt"),
|
||||
label.TraefikFrontendAuthForwardTLSCaOptional: aws.String("true"),
|
||||
label.TraefikFrontendAuthForwardTLSCert: aws.String("server.crt"),
|
||||
label.TraefikFrontendAuthForwardTLSKey: aws.String("server.key"),
|
||||
label.TraefikFrontendAuthForwardTLSInsecureSkipVerify: aws.String("true"),
|
||||
label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
|
||||
label.TraefikFrontendEntryPoints: aws.String("http,https"),
|
||||
label.TraefikFrontendPassHostHeader: aws.String("true"),
|
||||
label.TraefikFrontendPassTLSCert: aws.String("true"),
|
||||
label.TraefikFrontendPriority: aws.String("666"),
|
||||
label.TraefikFrontendRedirectEntryPoint: aws.String("https"),
|
||||
label.TraefikFrontendRedirectRegex: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectReplacement: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectPermanent: aws.String("true"),
|
||||
label.TraefikFrontendRule: aws.String("Host:traefik.io"),
|
||||
label.TraefikFrontendWhiteListSourceRange: aws.String("10.10.10.10"),
|
||||
label.TraefikFrontendWhiteListIPStrategyExcludedIPS: aws.String("10.10.10.10,10.10.10.11"),
|
||||
label.TraefikFrontendWhiteListIPStrategyDepth: aws.String("5"),
|
||||
label.TraefikFrontendEntryPoints: aws.String("http,https"),
|
||||
label.TraefikFrontendPassHostHeader: aws.String("true"),
|
||||
label.TraefikFrontendPassTLSCert: aws.String("true"),
|
||||
label.TraefikFrontendPriority: aws.String("666"),
|
||||
label.TraefikFrontendRedirectEntryPoint: aws.String("https"),
|
||||
label.TraefikFrontendRedirectRegex: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectReplacement: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectPermanent: aws.String("true"),
|
||||
label.TraefikFrontendRule: aws.String("Host:traefik.io"),
|
||||
label.TraefikFrontendWhiteListSourceRange: aws.String("10.10.10.10"),
|
||||
label.TraefikFrontendWhiteListIPStrategyExcludedIPS: aws.String("10.10.10.10,10.10.10.11"),
|
||||
label.TraefikFrontendWhiteListIPStrategyDepth: aws.String("5"),
|
||||
|
||||
label.TraefikFrontendRequestHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendResponseHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendSSLProxyHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendAllowedHosts: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendHostsProxyHeaders: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendSSLHost: aws.String("foo"),
|
||||
label.TraefikFrontendCustomFrameOptionsValue: aws.String("foo"),
|
||||
label.TraefikFrontendContentSecurityPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendPublicKey: aws.String("foo"),
|
||||
label.TraefikFrontendReferrerPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendCustomBrowserXSSValue: aws.String("foo"),
|
||||
label.TraefikFrontendSTSSeconds: aws.String("666"),
|
||||
label.TraefikFrontendSSLForceHost: aws.String("true"),
|
||||
label.TraefikFrontendSSLRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSSLTemporaryRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSTSIncludeSubdomains: aws.String("true"),
|
||||
label.TraefikFrontendSTSPreload: aws.String("true"),
|
||||
label.TraefikFrontendForceSTSHeader: aws.String("true"),
|
||||
label.TraefikFrontendFrameDeny: aws.String("true"),
|
||||
label.TraefikFrontendContentTypeNosniff: aws.String("true"),
|
||||
label.TraefikFrontendBrowserXSSFilter: aws.String("true"),
|
||||
label.TraefikFrontendIsDevelopment: aws.String("true"),
|
||||
label.TraefikFrontendRequestHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendResponseHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendSSLProxyHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendAllowedHosts: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendHostsProxyHeaders: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendSSLHost: aws.String("foo"),
|
||||
label.TraefikFrontendCustomFrameOptionsValue: aws.String("foo"),
|
||||
label.TraefikFrontendContentSecurityPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendPublicKey: aws.String("foo"),
|
||||
label.TraefikFrontendReferrerPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendCustomBrowserXSSValue: aws.String("foo"),
|
||||
label.TraefikFrontendSTSSeconds: aws.String("666"),
|
||||
label.TraefikFrontendSSLForceHost: aws.String("true"),
|
||||
label.TraefikFrontendSSLRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSSLTemporaryRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSTSIncludeSubdomains: aws.String("true"),
|
||||
label.TraefikFrontendSTSPreload: aws.String("true"),
|
||||
label.TraefikFrontendForceSTSHeader: aws.String("true"),
|
||||
label.TraefikFrontendFrameDeny: aws.String("true"),
|
||||
label.TraefikFrontendContentTypeNosniff: aws.String("true"),
|
||||
label.TraefikFrontendBrowserXSSFilter: aws.String("true"),
|
||||
label.TraefikFrontendIsDevelopment: aws.String("true"),
|
||||
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: aws.String("404"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageQuery: aws.String("foo_query"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageStatus: aws.String("500,600"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageQuery: aws.String("bar_query"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: aws.String("404"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageQuery: aws.String("foo_query"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageStatus: aws.String("500,600"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageQuery: aws.String("bar_query"),
|
||||
|
||||
label.TraefikFrontendRateLimitExtractorFunc: aws.String("client.ip"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitPeriod: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitAverage: aws.String("12"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitBurst: aws.String("18"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitPeriod: aws.String("3"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitAverage: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitBurst: aws.String("9"),
|
||||
}},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
privateIP: "10.0.0.1",
|
||||
ports: []portMapping{{hostPort: 1337}},
|
||||
},
|
||||
},
|
||||
label.TraefikFrontendRateLimitExtractorFunc: aws.String("client.ip"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitPeriod: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitAverage: aws.String("12"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitBurst: aws.String("18"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitPeriod: aws.String("3"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitAverage: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitBurst: aws.String("9"),
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("10.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 1337),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expected: &types.Configuration{
|
||||
Backends: map[string]*types.Backend{
|
||||
|
@ -585,176 +591,178 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
{
|
||||
desc: "Containers with same backend name",
|
||||
instances: []ecsInstance{
|
||||
{
|
||||
Name: "testing-instance-v1",
|
||||
ID: "6",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{
|
||||
label.TraefikPort: aws.String("666"),
|
||||
label.TraefikProtocol: aws.String("https"),
|
||||
label.TraefikWeight: aws.String("12"),
|
||||
instance(
|
||||
name("testing-instance-v1"),
|
||||
ID("6"),
|
||||
dockerLabels(map[string]*string{
|
||||
label.TraefikPort: aws.String("666"),
|
||||
label.TraefikProtocol: aws.String("https"),
|
||||
label.TraefikWeight: aws.String("12"),
|
||||
|
||||
label.TraefikBackend: aws.String("foobar"),
|
||||
label.TraefikBackend: aws.String("foobar"),
|
||||
|
||||
label.TraefikBackendCircuitBreakerExpression: aws.String("NetworkErrorRatio() > 0.5"),
|
||||
label.TraefikBackendHealthCheckScheme: aws.String("http"),
|
||||
label.TraefikBackendHealthCheckPath: aws.String("/health"),
|
||||
label.TraefikBackendHealthCheckPort: aws.String("880"),
|
||||
label.TraefikBackendHealthCheckInterval: aws.String("6"),
|
||||
label.TraefikBackendHealthCheckHostname: aws.String("foo.com"),
|
||||
label.TraefikBackendHealthCheckHeaders: aws.String("Foo:bar || Bar:foo"),
|
||||
label.TraefikBackendLoadBalancerMethod: aws.String("drr"),
|
||||
label.TraefikBackendLoadBalancerStickiness: aws.String("true"),
|
||||
label.TraefikBackendLoadBalancerStickinessCookieName: aws.String("chocolate"),
|
||||
label.TraefikBackendMaxConnAmount: aws.String("666"),
|
||||
label.TraefikBackendMaxConnExtractorFunc: aws.String("client.ip"),
|
||||
label.TraefikBackendBufferingMaxResponseBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemResponseBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingMaxRequestBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemRequestBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingRetryExpression: aws.String("IsNetworkError() && Attempts() <= 2"),
|
||||
label.TraefikBackendCircuitBreakerExpression: aws.String("NetworkErrorRatio() > 0.5"),
|
||||
label.TraefikBackendHealthCheckScheme: aws.String("http"),
|
||||
label.TraefikBackendHealthCheckPath: aws.String("/health"),
|
||||
label.TraefikBackendHealthCheckPort: aws.String("880"),
|
||||
label.TraefikBackendHealthCheckInterval: aws.String("6"),
|
||||
label.TraefikBackendHealthCheckHostname: aws.String("foo.com"),
|
||||
label.TraefikBackendHealthCheckHeaders: aws.String("Foo:bar || Bar:foo"),
|
||||
label.TraefikBackendLoadBalancerMethod: aws.String("drr"),
|
||||
label.TraefikBackendLoadBalancerStickiness: aws.String("true"),
|
||||
label.TraefikBackendLoadBalancerStickinessCookieName: aws.String("chocolate"),
|
||||
label.TraefikBackendMaxConnAmount: aws.String("666"),
|
||||
label.TraefikBackendMaxConnExtractorFunc: aws.String("client.ip"),
|
||||
label.TraefikBackendBufferingMaxResponseBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemResponseBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingMaxRequestBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemRequestBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingRetryExpression: aws.String("IsNetworkError() && Attempts() <= 2"),
|
||||
|
||||
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendEntryPoints: aws.String("http,https"),
|
||||
label.TraefikFrontendPassHostHeader: aws.String("true"),
|
||||
label.TraefikFrontendPassTLSCert: aws.String("true"),
|
||||
label.TraefikFrontendPriority: aws.String("666"),
|
||||
label.TraefikFrontendRedirectEntryPoint: aws.String("https"),
|
||||
label.TraefikFrontendRedirectRegex: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectReplacement: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectPermanent: aws.String("true"),
|
||||
label.TraefikFrontendRule: aws.String("Host:traefik.io"),
|
||||
label.TraefikFrontendWhiteListSourceRange: aws.String("10.10.10.10"),
|
||||
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendEntryPoints: aws.String("http,https"),
|
||||
label.TraefikFrontendPassHostHeader: aws.String("true"),
|
||||
label.TraefikFrontendPassTLSCert: aws.String("true"),
|
||||
label.TraefikFrontendPriority: aws.String("666"),
|
||||
label.TraefikFrontendRedirectEntryPoint: aws.String("https"),
|
||||
label.TraefikFrontendRedirectRegex: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectReplacement: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectPermanent: aws.String("true"),
|
||||
label.TraefikFrontendRule: aws.String("Host:traefik.io"),
|
||||
label.TraefikFrontendWhiteListSourceRange: aws.String("10.10.10.10"),
|
||||
|
||||
label.TraefikFrontendRequestHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendResponseHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendSSLProxyHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendAllowedHosts: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendHostsProxyHeaders: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendSSLHost: aws.String("foo"),
|
||||
label.TraefikFrontendCustomFrameOptionsValue: aws.String("foo"),
|
||||
label.TraefikFrontendContentSecurityPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendPublicKey: aws.String("foo"),
|
||||
label.TraefikFrontendReferrerPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendCustomBrowserXSSValue: aws.String("foo"),
|
||||
label.TraefikFrontendSTSSeconds: aws.String("666"),
|
||||
label.TraefikFrontendSSLForceHost: aws.String("true"),
|
||||
label.TraefikFrontendSSLRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSSLTemporaryRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSTSIncludeSubdomains: aws.String("true"),
|
||||
label.TraefikFrontendSTSPreload: aws.String("true"),
|
||||
label.TraefikFrontendForceSTSHeader: aws.String("true"),
|
||||
label.TraefikFrontendFrameDeny: aws.String("true"),
|
||||
label.TraefikFrontendContentTypeNosniff: aws.String("true"),
|
||||
label.TraefikFrontendBrowserXSSFilter: aws.String("true"),
|
||||
label.TraefikFrontendIsDevelopment: aws.String("true"),
|
||||
label.TraefikFrontendRequestHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendResponseHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendSSLProxyHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendAllowedHosts: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendHostsProxyHeaders: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendSSLHost: aws.String("foo"),
|
||||
label.TraefikFrontendCustomFrameOptionsValue: aws.String("foo"),
|
||||
label.TraefikFrontendContentSecurityPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendPublicKey: aws.String("foo"),
|
||||
label.TraefikFrontendReferrerPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendCustomBrowserXSSValue: aws.String("foo"),
|
||||
label.TraefikFrontendSTSSeconds: aws.String("666"),
|
||||
label.TraefikFrontendSSLForceHost: aws.String("true"),
|
||||
label.TraefikFrontendSSLRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSSLTemporaryRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSTSIncludeSubdomains: aws.String("true"),
|
||||
label.TraefikFrontendSTSPreload: aws.String("true"),
|
||||
label.TraefikFrontendForceSTSHeader: aws.String("true"),
|
||||
label.TraefikFrontendFrameDeny: aws.String("true"),
|
||||
label.TraefikFrontendContentTypeNosniff: aws.String("true"),
|
||||
label.TraefikFrontendBrowserXSSFilter: aws.String("true"),
|
||||
label.TraefikFrontendIsDevelopment: aws.String("true"),
|
||||
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: aws.String("404"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageQuery: aws.String("foo_query"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageStatus: aws.String("500,600"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageQuery: aws.String("bar_query"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: aws.String("404"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageQuery: aws.String("foo_query"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageStatus: aws.String("500,600"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageQuery: aws.String("bar_query"),
|
||||
|
||||
label.TraefikFrontendRateLimitExtractorFunc: aws.String("client.ip"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitPeriod: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitAverage: aws.String("12"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitBurst: aws.String("18"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitPeriod: aws.String("3"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitAverage: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitBurst: aws.String("9"),
|
||||
}},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
privateIP: "10.0.0.1",
|
||||
ports: []portMapping{{hostPort: 1337}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "testing-instance-v2",
|
||||
ID: "6",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{
|
||||
label.TraefikPort: aws.String("555"),
|
||||
label.TraefikProtocol: aws.String("https"),
|
||||
label.TraefikWeight: aws.String("15"),
|
||||
label.TraefikFrontendRateLimitExtractorFunc: aws.String("client.ip"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitPeriod: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitAverage: aws.String("12"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitBurst: aws.String("18"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitPeriod: aws.String("3"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitAverage: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitBurst: aws.String("9"),
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("10.0.0.1"),
|
||||
mPorts(
|
||||
mPort(0, 1337),
|
||||
),
|
||||
),
|
||||
),
|
||||
instance(
|
||||
name("testing-instance-v2"),
|
||||
ID("6"),
|
||||
dockerLabels(map[string]*string{
|
||||
label.TraefikPort: aws.String("555"),
|
||||
label.TraefikProtocol: aws.String("https"),
|
||||
label.TraefikWeight: aws.String("15"),
|
||||
|
||||
label.TraefikBackend: aws.String("foobar"),
|
||||
label.TraefikBackend: aws.String("foobar"),
|
||||
|
||||
label.TraefikBackendCircuitBreakerExpression: aws.String("NetworkErrorRatio() > 0.5"),
|
||||
label.TraefikBackendHealthCheckScheme: aws.String("http"),
|
||||
label.TraefikBackendHealthCheckPath: aws.String("/health"),
|
||||
label.TraefikBackendHealthCheckPort: aws.String("880"),
|
||||
label.TraefikBackendHealthCheckInterval: aws.String("6"),
|
||||
label.TraefikBackendHealthCheckHostname: aws.String("bar.com"),
|
||||
label.TraefikBackendHealthCheckHeaders: aws.String("Foo:bar || Bar:foo"),
|
||||
label.TraefikBackendLoadBalancerMethod: aws.String("drr"),
|
||||
label.TraefikBackendLoadBalancerStickiness: aws.String("true"),
|
||||
label.TraefikBackendLoadBalancerStickinessCookieName: aws.String("chocolate"),
|
||||
label.TraefikBackendMaxConnAmount: aws.String("666"),
|
||||
label.TraefikBackendMaxConnExtractorFunc: aws.String("client.ip"),
|
||||
label.TraefikBackendBufferingMaxResponseBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemResponseBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingMaxRequestBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemRequestBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingRetryExpression: aws.String("IsNetworkError() && Attempts() <= 2"),
|
||||
label.TraefikBackendCircuitBreakerExpression: aws.String("NetworkErrorRatio() > 0.5"),
|
||||
label.TraefikBackendHealthCheckScheme: aws.String("http"),
|
||||
label.TraefikBackendHealthCheckPath: aws.String("/health"),
|
||||
label.TraefikBackendHealthCheckPort: aws.String("880"),
|
||||
label.TraefikBackendHealthCheckInterval: aws.String("6"),
|
||||
label.TraefikBackendHealthCheckHostname: aws.String("bar.com"),
|
||||
label.TraefikBackendHealthCheckHeaders: aws.String("Foo:bar || Bar:foo"),
|
||||
label.TraefikBackendLoadBalancerMethod: aws.String("drr"),
|
||||
label.TraefikBackendLoadBalancerStickiness: aws.String("true"),
|
||||
label.TraefikBackendLoadBalancerStickinessCookieName: aws.String("chocolate"),
|
||||
label.TraefikBackendMaxConnAmount: aws.String("666"),
|
||||
label.TraefikBackendMaxConnExtractorFunc: aws.String("client.ip"),
|
||||
label.TraefikBackendBufferingMaxResponseBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemResponseBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingMaxRequestBodyBytes: aws.String("10485760"),
|
||||
label.TraefikBackendBufferingMemRequestBodyBytes: aws.String("2097152"),
|
||||
label.TraefikBackendBufferingRetryExpression: aws.String("IsNetworkError() && Attempts() <= 2"),
|
||||
|
||||
label.TraefikFrontendAuthBasic: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendEntryPoints: aws.String("http,https"),
|
||||
label.TraefikFrontendPassHostHeader: aws.String("true"),
|
||||
label.TraefikFrontendPassTLSCert: aws.String("true"),
|
||||
label.TraefikFrontendPriority: aws.String("666"),
|
||||
label.TraefikFrontendRedirectEntryPoint: aws.String("https"),
|
||||
label.TraefikFrontendRedirectRegex: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectReplacement: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectPermanent: aws.String("true"),
|
||||
label.TraefikFrontendRule: aws.String("Host:traefik.io"),
|
||||
label.TraefikFrontendWhiteListSourceRange: aws.String("10.10.10.10"),
|
||||
label.TraefikFrontendAuthBasic: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendEntryPoints: aws.String("http,https"),
|
||||
label.TraefikFrontendPassHostHeader: aws.String("true"),
|
||||
label.TraefikFrontendPassTLSCert: aws.String("true"),
|
||||
label.TraefikFrontendPriority: aws.String("666"),
|
||||
label.TraefikFrontendRedirectEntryPoint: aws.String("https"),
|
||||
label.TraefikFrontendRedirectRegex: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectReplacement: aws.String("nope"),
|
||||
label.TraefikFrontendRedirectPermanent: aws.String("true"),
|
||||
label.TraefikFrontendRule: aws.String("Host:traefik.io"),
|
||||
label.TraefikFrontendWhiteListSourceRange: aws.String("10.10.10.10"),
|
||||
|
||||
label.TraefikFrontendRequestHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendResponseHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendSSLProxyHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendAllowedHosts: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendHostsProxyHeaders: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendSSLHost: aws.String("foo"),
|
||||
label.TraefikFrontendCustomFrameOptionsValue: aws.String("foo"),
|
||||
label.TraefikFrontendContentSecurityPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendPublicKey: aws.String("foo"),
|
||||
label.TraefikFrontendReferrerPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendCustomBrowserXSSValue: aws.String("foo"),
|
||||
label.TraefikFrontendSTSSeconds: aws.String("666"),
|
||||
label.TraefikFrontendSSLForceHost: aws.String("true"),
|
||||
label.TraefikFrontendSSLRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSSLTemporaryRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSTSIncludeSubdomains: aws.String("true"),
|
||||
label.TraefikFrontendSTSPreload: aws.String("true"),
|
||||
label.TraefikFrontendForceSTSHeader: aws.String("true"),
|
||||
label.TraefikFrontendFrameDeny: aws.String("true"),
|
||||
label.TraefikFrontendContentTypeNosniff: aws.String("true"),
|
||||
label.TraefikFrontendBrowserXSSFilter: aws.String("true"),
|
||||
label.TraefikFrontendIsDevelopment: aws.String("true"),
|
||||
label.TraefikFrontendRequestHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendResponseHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendSSLProxyHeaders: aws.String("Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"),
|
||||
label.TraefikFrontendAllowedHosts: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendHostsProxyHeaders: aws.String("foo,bar,bor"),
|
||||
label.TraefikFrontendSSLHost: aws.String("foo"),
|
||||
label.TraefikFrontendCustomFrameOptionsValue: aws.String("foo"),
|
||||
label.TraefikFrontendContentSecurityPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendPublicKey: aws.String("foo"),
|
||||
label.TraefikFrontendReferrerPolicy: aws.String("foo"),
|
||||
label.TraefikFrontendCustomBrowserXSSValue: aws.String("foo"),
|
||||
label.TraefikFrontendSTSSeconds: aws.String("666"),
|
||||
label.TraefikFrontendSSLForceHost: aws.String("true"),
|
||||
label.TraefikFrontendSSLRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSSLTemporaryRedirect: aws.String("true"),
|
||||
label.TraefikFrontendSTSIncludeSubdomains: aws.String("true"),
|
||||
label.TraefikFrontendSTSPreload: aws.String("true"),
|
||||
label.TraefikFrontendForceSTSHeader: aws.String("true"),
|
||||
label.TraefikFrontendFrameDeny: aws.String("true"),
|
||||
label.TraefikFrontendContentTypeNosniff: aws.String("true"),
|
||||
label.TraefikFrontendBrowserXSSFilter: aws.String("true"),
|
||||
label.TraefikFrontendIsDevelopment: aws.String("true"),
|
||||
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: aws.String("404"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageQuery: aws.String("foo_query"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageStatus: aws.String("500,600"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageQuery: aws.String("bar_query"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: aws.String("404"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageQuery: aws.String("foo_query"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageStatus: aws.String("500,600"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageBackend: aws.String("foobar"),
|
||||
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageQuery: aws.String("bar_query"),
|
||||
|
||||
label.TraefikFrontendRateLimitExtractorFunc: aws.String("client.ip"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitPeriod: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitAverage: aws.String("12"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitBurst: aws.String("18"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitPeriod: aws.String("3"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitAverage: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitBurst: aws.String("9"),
|
||||
}},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
privateIP: "10.2.2.1",
|
||||
ports: []portMapping{{hostPort: 1337}},
|
||||
},
|
||||
},
|
||||
label.TraefikFrontendRateLimitExtractorFunc: aws.String("client.ip"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitPeriod: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitAverage: aws.String("12"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitBurst: aws.String("18"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitPeriod: aws.String("3"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitAverage: aws.String("6"),
|
||||
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitBurst: aws.String("9"),
|
||||
}),
|
||||
iMachine(
|
||||
mState(ec2.InstanceStateNameRunning),
|
||||
mPrivateIP("10.2.2.1"),
|
||||
mPorts(
|
||||
mPort(0, 1337),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
expected: &types.Configuration{
|
||||
Backends: map[string]*types.Backend{
|
||||
|
|
|
@ -45,6 +45,8 @@ type ecsInstance struct {
|
|||
containerDefinition *ecs.ContainerDefinition
|
||||
machine *machine
|
||||
TraefikLabels map[string]string
|
||||
SegmentLabels map[string]string
|
||||
SegmentName string
|
||||
}
|
||||
|
||||
type portMapping struct {
|
||||
|
|
|
@ -122,40 +122,36 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
|||
|
||||
pool.Go(func(stop chan bool) {
|
||||
operation := func() error {
|
||||
for {
|
||||
stopWatch := make(chan struct{}, 1)
|
||||
defer close(stopWatch)
|
||||
eventsChan, err := k8sClient.WatchAll(p.Namespaces, stopWatch)
|
||||
if err != nil {
|
||||
log.Errorf("Error watching kubernetes events: %v", err)
|
||||
timer := time.NewTimer(1 * time.Second)
|
||||
select {
|
||||
case <-timer.C:
|
||||
return err
|
||||
case <-stop:
|
||||
return nil
|
||||
}
|
||||
stopWatch := make(chan struct{}, 1)
|
||||
defer close(stopWatch)
|
||||
eventsChan, err := k8sClient.WatchAll(p.Namespaces, stopWatch)
|
||||
if err != nil {
|
||||
log.Errorf("Error watching kubernetes events: %v", err)
|
||||
timer := time.NewTimer(1 * time.Second)
|
||||
select {
|
||||
case <-timer.C:
|
||||
return err
|
||||
case <-stop:
|
||||
return nil
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return nil
|
||||
case event := <-eventsChan:
|
||||
log.Debugf("Received Kubernetes event kind %T", event)
|
||||
|
||||
templateObjects, err := p.loadIngresses(k8sClient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(p.lastConfiguration.Get(), templateObjects) {
|
||||
log.Debugf("Skipping Kubernetes event kind %T", event)
|
||||
} else {
|
||||
p.lastConfiguration.Set(templateObjects)
|
||||
configurationChan <- types.ConfigMessage{
|
||||
ProviderName: "kubernetes",
|
||||
Configuration: p.loadConfig(*templateObjects),
|
||||
}
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return nil
|
||||
case event := <-eventsChan:
|
||||
log.Debugf("Received Kubernetes event kind %T", event)
|
||||
templateObjects, err := p.loadIngresses(k8sClient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if reflect.DeepEqual(p.lastConfiguration.Get(), templateObjects) {
|
||||
log.Debugf("Skipping Kubernetes event kind %T", event)
|
||||
} else {
|
||||
p.lastConfiguration.Set(templateObjects)
|
||||
configurationChan <- types.ConfigMessage{
|
||||
ProviderName: "kubernetes",
|
||||
Configuration: p.loadConfig(*templateObjects),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -224,7 +220,12 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
|||
}
|
||||
|
||||
for _, pa := range r.HTTP.Paths {
|
||||
priority := getIntValue(i.Annotations, annotationKubernetesPriority, 0)
|
||||
baseName := r.Host + pa.Path
|
||||
if priority > 0 {
|
||||
baseName = strconv.Itoa(priority) + "-" + baseName
|
||||
}
|
||||
|
||||
if _, exists := templateObjects.Backends[baseName]; !exists {
|
||||
templateObjects.Backends[baseName] = &types.Backend{
|
||||
Servers: make(map[string]types.Server),
|
||||
|
@ -250,7 +251,6 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
|||
|
||||
passHostHeader := getBoolValue(i.Annotations, annotationKubernetesPreserveHost, !p.DisablePassHostHeaders)
|
||||
passTLSCert := getBoolValue(i.Annotations, annotationKubernetesPassTLSCert, p.EnablePassTLSCert)
|
||||
priority := getIntValue(i.Annotations, annotationKubernetesPriority, 0)
|
||||
entryPoints := getSliceStringValue(i.Annotations, annotationKubernetesFrontendEntryPoints)
|
||||
|
||||
templateObjects.Frontends[baseName] = &types.Frontend{
|
||||
|
@ -883,7 +883,19 @@ func getFrontendRedirect(i *extensionsv1beta1.Ingress, baseName, path string) *t
|
|||
}
|
||||
|
||||
redirectRegex := getStringValue(i.Annotations, annotationKubernetesRedirectRegex, "")
|
||||
_, err := strconv.Unquote(`"` + redirectRegex + `"`)
|
||||
if err != nil {
|
||||
log.Debugf("Skipping Redirect on Ingress %s/%s due to invalid regex: %s", i.Namespace, i.Name, redirectRegex)
|
||||
return nil
|
||||
}
|
||||
|
||||
redirectReplacement := getStringValue(i.Annotations, annotationKubernetesRedirectReplacement, "")
|
||||
_, err = strconv.Unquote(`"` + redirectReplacement + `"`)
|
||||
if err != nil {
|
||||
log.Debugf("Skipping Redirect on Ingress %s/%s due to invalid replacement: %q", i.Namespace, i.Name, redirectRegex)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(redirectRegex) > 0 && len(redirectReplacement) > 0 {
|
||||
return &types.Redirect{
|
||||
Regex: redirectRegex,
|
||||
|
|
|
@ -740,6 +740,34 @@ func TestGetPassTLSCert(t *testing.T) {
|
|||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestInvalidRedirectAnnotation(t *testing.T) {
|
||||
ingresses := []*extensionsv1beta1.Ingress{
|
||||
buildIngress(iNamespace("awesome"),
|
||||
iAnnotation(annotationKubernetesRedirectRegex, `bad\.regex`),
|
||||
iAnnotation(annotationKubernetesRedirectReplacement, "test"),
|
||||
iRules(iRule(
|
||||
iHost("foo"),
|
||||
iPaths(onePath(iPath("/bar"), iBackend("service1", intstr.FromInt(80))))),
|
||||
),
|
||||
),
|
||||
buildIngress(iNamespace("awesome"),
|
||||
iAnnotation(annotationKubernetesRedirectRegex, `test`),
|
||||
iAnnotation(annotationKubernetesRedirectReplacement, `bad\.replacement`),
|
||||
iRules(iRule(
|
||||
iHost("foo"),
|
||||
iPaths(onePath(iPath("/bar"), iBackend("service1", intstr.FromInt(80))))),
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
for _, ingress := range ingresses {
|
||||
actual := getFrontendRedirect(ingress, "test", "/")
|
||||
var expected *types.Redirect
|
||||
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOnlyReferencesServicesFromOwnNamespace(t *testing.T) {
|
||||
ingresses := []*extensionsv1beta1.Ingress{
|
||||
buildIngress(iNamespace("awesome"),
|
||||
|
@ -1847,13 +1875,13 @@ func TestPriorityHeaderValue(t *testing.T) {
|
|||
|
||||
expected := buildConfiguration(
|
||||
backends(
|
||||
backend("foo/bar",
|
||||
backend("1337-foo/bar",
|
||||
servers(server("http://example.com", weight(1))),
|
||||
lbMethod("wrr"),
|
||||
),
|
||||
),
|
||||
frontends(
|
||||
frontend("foo/bar",
|
||||
frontend("1337-foo/bar",
|
||||
passHostHeader(),
|
||||
priority(1337),
|
||||
routes(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue