Segments Labels: Rancher & Marathon
This commit is contained in:
parent
16bb9b6836
commit
0ea007b26f
31 changed files with 4288 additions and 3656 deletions
|
@ -7,9 +7,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/flaeg"
|
||||
"github.com/containous/traefik/log"
|
||||
"github.com/containous/traefik/types"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -28,7 +26,6 @@ const (
|
|||
DefaultFrontendPriority = "0" // TODO [breaking] int value
|
||||
DefaultFrontendPriorityInt = 0 // TODO rename to DefaultFrontendPriority
|
||||
DefaultCircuitBreakerExpression = "NetworkErrorRatio() > 1"
|
||||
DefaultFrontendRedirectEntryPoint = ""
|
||||
DefaultBackendLoadBalancerMethod = "wrr"
|
||||
DefaultBackendMaxconnExtractorFunc = "request.host"
|
||||
DefaultBackendLoadbalancerStickinessCookieName = ""
|
||||
|
@ -57,14 +54,6 @@ func GetStringValue(labels map[string]string, labelName string, defaultValue str
|
|||
return defaultValue
|
||||
}
|
||||
|
||||
// GetStringValueP get string value associated to a label
|
||||
func GetStringValueP(labels *map[string]string, labelName string, defaultValue string) string {
|
||||
if labels == nil {
|
||||
return defaultValue
|
||||
}
|
||||
return GetStringValue(*labels, labelName, defaultValue)
|
||||
}
|
||||
|
||||
// GetBoolValue get bool value associated to a label
|
||||
func GetBoolValue(labels map[string]string, labelName string, defaultValue bool) bool {
|
||||
rawValue, ok := labels[labelName]
|
||||
|
@ -77,14 +66,6 @@ func GetBoolValue(labels map[string]string, labelName string, defaultValue bool)
|
|||
return defaultValue
|
||||
}
|
||||
|
||||
// GetBoolValueP get bool value associated to a label
|
||||
func GetBoolValueP(labels *map[string]string, labelName string, defaultValue bool) bool {
|
||||
if labels == nil {
|
||||
return defaultValue
|
||||
}
|
||||
return GetBoolValue(*labels, labelName, defaultValue)
|
||||
}
|
||||
|
||||
// GetIntValue get int value associated to a label
|
||||
func GetIntValue(labels map[string]string, labelName string, defaultValue int) int {
|
||||
if rawValue, ok := labels[labelName]; ok {
|
||||
|
@ -97,14 +78,6 @@ func GetIntValue(labels map[string]string, labelName string, defaultValue int) i
|
|||
return defaultValue
|
||||
}
|
||||
|
||||
// GetIntValueP get int value associated to a label
|
||||
func GetIntValueP(labels *map[string]string, labelName string, defaultValue int) int {
|
||||
if labels == nil {
|
||||
return defaultValue
|
||||
}
|
||||
return GetIntValue(*labels, labelName, defaultValue)
|
||||
}
|
||||
|
||||
// GetInt64Value get int64 value associated to a label
|
||||
func GetInt64Value(labels map[string]string, labelName string, defaultValue int64) int64 {
|
||||
if rawValue, ok := labels[labelName]; ok {
|
||||
|
@ -117,14 +90,6 @@ func GetInt64Value(labels map[string]string, labelName string, defaultValue int6
|
|||
return defaultValue
|
||||
}
|
||||
|
||||
// GetInt64ValueP get int64 value associated to a label
|
||||
func GetInt64ValueP(labels *map[string]string, labelName string, defaultValue int64) int64 {
|
||||
if labels == nil {
|
||||
return defaultValue
|
||||
}
|
||||
return GetInt64Value(*labels, labelName, defaultValue)
|
||||
}
|
||||
|
||||
// GetSliceStringValue get a slice of string associated to a label
|
||||
func GetSliceStringValue(labels map[string]string, labelName string) []string {
|
||||
var value []string
|
||||
|
@ -139,14 +104,6 @@ func GetSliceStringValue(labels map[string]string, labelName string) []string {
|
|||
return value
|
||||
}
|
||||
|
||||
// GetSliceStringValueP get a slice of string value associated to a label
|
||||
func GetSliceStringValueP(labels *map[string]string, labelName string) []string {
|
||||
if labels == nil {
|
||||
return nil
|
||||
}
|
||||
return GetSliceStringValue(*labels, labelName)
|
||||
}
|
||||
|
||||
// ParseMapValue get Map value for a label value
|
||||
func ParseMapValue(labelName, values string) map[string]string {
|
||||
mapValue := make(map[string]string)
|
||||
|
@ -203,14 +160,6 @@ func Has(labels map[string]string, labelName string) bool {
|
|||
return ok && len(value) > 0
|
||||
}
|
||||
|
||||
// HasP Check if a value is associated to a label
|
||||
func HasP(labels *map[string]string, labelName string) bool {
|
||||
if labels == nil {
|
||||
return false
|
||||
}
|
||||
return Has(*labels, labelName)
|
||||
}
|
||||
|
||||
// HasPrefix Check if a value is associated to a less one label with a prefix
|
||||
func HasPrefix(labels map[string]string, prefix string) bool {
|
||||
for name, value := range labels {
|
||||
|
@ -221,124 +170,11 @@ func HasPrefix(labels map[string]string, prefix string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// HasPrefixP Check if a value is associated to a less one label with a prefix
|
||||
func HasPrefixP(labels *map[string]string, prefix string) bool {
|
||||
if labels == nil {
|
||||
return false
|
||||
}
|
||||
return HasPrefix(*labels, prefix)
|
||||
}
|
||||
|
||||
// ParseErrorPages parse error pages to create ErrorPage struct
|
||||
func ParseErrorPages(labels map[string]string, labelPrefix string, labelRegex *regexp.Regexp) map[string]*types.ErrorPage {
|
||||
var errorPages map[string]*types.ErrorPage
|
||||
|
||||
for lblName, value := range labels {
|
||||
if strings.HasPrefix(lblName, labelPrefix) {
|
||||
submatch := labelRegex.FindStringSubmatch(lblName)
|
||||
if len(submatch) != 3 {
|
||||
log.Errorf("Invalid page error label: %s, sub-match: %v", lblName, submatch)
|
||||
continue
|
||||
}
|
||||
|
||||
if errorPages == nil {
|
||||
errorPages = make(map[string]*types.ErrorPage)
|
||||
}
|
||||
|
||||
pageName := submatch[1]
|
||||
|
||||
ep, ok := errorPages[pageName]
|
||||
if !ok {
|
||||
ep = &types.ErrorPage{}
|
||||
errorPages[pageName] = ep
|
||||
}
|
||||
|
||||
switch submatch[2] {
|
||||
case SuffixErrorPageStatus:
|
||||
ep.Status = SplitAndTrimString(value, ",")
|
||||
case SuffixErrorPageQuery:
|
||||
ep.Query = value
|
||||
case SuffixErrorPageBackend:
|
||||
ep.Backend = value
|
||||
default:
|
||||
log.Errorf("Invalid page error label: %s", lblName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errorPages
|
||||
}
|
||||
|
||||
// ParseRateSets parse rate limits to create Rate struct
|
||||
func ParseRateSets(labels map[string]string, labelPrefix string, labelRegex *regexp.Regexp) map[string]*types.Rate {
|
||||
var rateSets map[string]*types.Rate
|
||||
|
||||
for lblName, rawValue := range labels {
|
||||
if strings.HasPrefix(lblName, labelPrefix) && len(rawValue) > 0 {
|
||||
submatch := labelRegex.FindStringSubmatch(lblName)
|
||||
if len(submatch) != 3 {
|
||||
log.Errorf("Invalid rate limit label: %s, sub-match: %v", lblName, submatch)
|
||||
continue
|
||||
}
|
||||
|
||||
if rateSets == nil {
|
||||
rateSets = make(map[string]*types.Rate)
|
||||
}
|
||||
|
||||
limitName := submatch[1]
|
||||
|
||||
ep, ok := rateSets[limitName]
|
||||
if !ok {
|
||||
ep = &types.Rate{}
|
||||
rateSets[limitName] = ep
|
||||
}
|
||||
|
||||
switch submatch[2] {
|
||||
case "period":
|
||||
var d flaeg.Duration
|
||||
err := d.Set(rawValue)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to parse %q: %q. %v", lblName, rawValue, err)
|
||||
continue
|
||||
}
|
||||
ep.Period = d
|
||||
case "average":
|
||||
value, err := strconv.ParseInt(rawValue, 10, 64)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to parse %q: %q. %v", lblName, rawValue, err)
|
||||
continue
|
||||
}
|
||||
ep.Average = value
|
||||
case "burst":
|
||||
value, err := strconv.ParseInt(rawValue, 10, 64)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to parse %q: %q. %v", lblName, rawValue, err)
|
||||
continue
|
||||
}
|
||||
ep.Burst = value
|
||||
default:
|
||||
log.Errorf("Invalid rate limit label: %s", lblName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return rateSets
|
||||
}
|
||||
|
||||
// IsEnabled Check if a container is enabled in Træfik
|
||||
func IsEnabled(labels map[string]string, exposedByDefault bool) bool {
|
||||
return GetBoolValue(labels, TraefikEnable, exposedByDefault)
|
||||
}
|
||||
|
||||
// IsEnabledP Check if a container is enabled in Træfik
|
||||
func IsEnabledP(labels *map[string]string, exposedByDefault bool) bool {
|
||||
if labels == nil {
|
||||
return exposedByDefault
|
||||
}
|
||||
return IsEnabled(*labels, exposedByDefault)
|
||||
}
|
||||
|
||||
// SplitAndTrimString splits separatedString at the separator character and trims each
|
||||
// piece, filtering out empty pieces. Returns the list of pieces or nil if the input
|
||||
// did not contain a non-empty piece.
|
||||
|
@ -354,3 +190,31 @@ func SplitAndTrimString(base string, sep string) []string {
|
|||
|
||||
return trimmedStrings
|
||||
}
|
||||
|
||||
// GetFuncString a func related to GetStringValue
|
||||
func GetFuncString(labelName string, defaultValue string) func(map[string]string) string {
|
||||
return func(labels map[string]string) string {
|
||||
return GetStringValue(labels, labelName, defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
// GetFuncInt a func related to GetIntValue
|
||||
func GetFuncInt(labelName string, defaultValue int) func(map[string]string) int {
|
||||
return func(labels map[string]string) int {
|
||||
return GetIntValue(labels, labelName, defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
// GetFuncBool a func related to GetBoolValue
|
||||
func GetFuncBool(labelName string, defaultValue bool) func(map[string]string) bool {
|
||||
return func(labels map[string]string) bool {
|
||||
return GetBoolValue(labels, labelName, defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
// GetFuncSliceString a func related to GetSliceStringValue
|
||||
func GetFuncSliceString(labelName string) func(map[string]string) []string {
|
||||
return func(labels map[string]string) []string {
|
||||
return GetSliceStringValue(labels, labelName)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package label
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containous/flaeg"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -108,51 +106,6 @@ func TestGetStringValue(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetStringValueP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels *map[string]string
|
||||
labelName string
|
||||
defaultValue string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "nil labels map",
|
||||
labels: nil,
|
||||
labelName: "foo",
|
||||
defaultValue: "default",
|
||||
expected: "default",
|
||||
},
|
||||
{
|
||||
desc: "existing label",
|
||||
labels: &map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
labelName: "foo",
|
||||
defaultValue: "default",
|
||||
expected: "bar",
|
||||
},
|
||||
{
|
||||
desc: "non existing label",
|
||||
labels: &map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
labelName: "fii",
|
||||
defaultValue: "default",
|
||||
expected: "default",
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := GetStringValueP(test.labels, test.labelName, test.defaultValue)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBoolValue(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -255,60 +208,6 @@ func TestGetIntValue(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetIntValueP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels *map[string]string
|
||||
labelName string
|
||||
defaultValue int
|
||||
expected int
|
||||
}{
|
||||
{
|
||||
desc: "nil map",
|
||||
labels: nil,
|
||||
labelName: "foo",
|
||||
defaultValue: 666,
|
||||
expected: 666,
|
||||
},
|
||||
{
|
||||
desc: "invalid int value",
|
||||
labelName: "foo",
|
||||
labels: &map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
defaultValue: 666,
|
||||
expected: 666,
|
||||
},
|
||||
{
|
||||
desc: "negative int value",
|
||||
labelName: "foo",
|
||||
labels: &map[string]string{
|
||||
"foo": "-1",
|
||||
},
|
||||
defaultValue: 666,
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
desc: "positive int value",
|
||||
labelName: "foo",
|
||||
labels: &map[string]string{
|
||||
"foo": "1",
|
||||
},
|
||||
defaultValue: 666,
|
||||
expected: 1,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := GetIntValueP(test.labels, test.labelName, test.defaultValue)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetInt64Value(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -360,60 +259,6 @@ func TestGetInt64Value(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetInt64ValueP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels *map[string]string
|
||||
labelName string
|
||||
defaultValue int64
|
||||
expected int64
|
||||
}{
|
||||
{
|
||||
desc: "nil map",
|
||||
labels: nil,
|
||||
labelName: "foo",
|
||||
defaultValue: 666,
|
||||
expected: 666,
|
||||
},
|
||||
{
|
||||
desc: "invalid int value",
|
||||
labelName: "foo",
|
||||
labels: &map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
defaultValue: 666,
|
||||
expected: 666,
|
||||
},
|
||||
{
|
||||
desc: "negative int value",
|
||||
labelName: "foo",
|
||||
labels: &map[string]string{
|
||||
"foo": "-1",
|
||||
},
|
||||
defaultValue: 666,
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
desc: "positive int value",
|
||||
labelName: "foo",
|
||||
labels: &map[string]string{
|
||||
"foo": "1",
|
||||
},
|
||||
defaultValue: 666,
|
||||
expected: 1,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := GetInt64ValueP(test.labels, test.labelName, test.defaultValue)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSliceStringValue(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -461,47 +306,6 @@ func TestGetSliceStringValue(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetSliceStringValueP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels *map[string]string
|
||||
labelName string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
desc: "nil map",
|
||||
labels: nil,
|
||||
labelName: "foo",
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "one value, not split",
|
||||
labels: &map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
labelName: "foo",
|
||||
expected: []string{"bar"},
|
||||
},
|
||||
{
|
||||
desc: "several values",
|
||||
labels: &map[string]string{
|
||||
"foo": "bar,bir ,bur",
|
||||
},
|
||||
labelName: "foo",
|
||||
expected: []string{"bar", "bir", "bur"},
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := GetSliceStringValueP(test.labels, test.labelName)
|
||||
assert.EqualValues(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMapValue(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -680,149 +484,6 @@ func TestHas(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestHasP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels *map[string]string
|
||||
labelName string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
desc: "nil labels map",
|
||||
labelName: "foo",
|
||||
},
|
||||
{
|
||||
desc: "nonexistent label",
|
||||
labels: &map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
labelName: "fii",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "existent label",
|
||||
labels: &map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
labelName: "foo",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "existent label with empty value",
|
||||
labels: &map[string]string{
|
||||
"foo": "",
|
||||
},
|
||||
labelName: "foo",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := HasP(test.labels, test.labelName)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractServiceProperties(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected SegmentProperties
|
||||
}{
|
||||
{
|
||||
desc: "empty labels map",
|
||||
expected: SegmentProperties{},
|
||||
},
|
||||
{
|
||||
desc: "valid label names",
|
||||
labels: map[string]string{
|
||||
"traefik.foo.port": "bar",
|
||||
"traefik.foo.frontend.bar": "1bar",
|
||||
"traefik.foo.backend": "3bar",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"foo": SegmentPropertyValues{
|
||||
"port": "bar",
|
||||
"frontend.bar": "1bar",
|
||||
"backend": "3bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "invalid label names",
|
||||
labels: map[string]string{
|
||||
"foo.frontend.bar": "1bar",
|
||||
"traefik.foo.frontend.": "2bar",
|
||||
"traefik.foo.port.bar": "barbar",
|
||||
"traefik.foo.frontend": "0bar",
|
||||
"traefik.frontend.foo.backend": "0bar",
|
||||
},
|
||||
expected: SegmentProperties{},
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := ExtractServiceProperties(test.labels)
|
||||
assert.EqualValues(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractServicePropertiesP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels *map[string]string
|
||||
expected SegmentProperties
|
||||
}{
|
||||
{
|
||||
desc: "nil labels map",
|
||||
expected: SegmentProperties{},
|
||||
},
|
||||
{
|
||||
desc: "valid label names",
|
||||
labels: &map[string]string{
|
||||
"traefik.foo.port": "bar",
|
||||
"traefik.foo.frontend.bar": "1bar",
|
||||
"traefik.foo.backend": "3bar",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"foo": SegmentPropertyValues{
|
||||
"port": "bar",
|
||||
"frontend.bar": "1bar",
|
||||
"backend": "3bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "invalid label names",
|
||||
labels: &map[string]string{
|
||||
"foo.frontend.bar": "1bar",
|
||||
"traefik.foo.frontend.": "2bar",
|
||||
"traefik.foo.port.bar": "barbar",
|
||||
"traefik.foo.frontend": "0bar",
|
||||
"traefik.frontend.foo.backend": "0bar",
|
||||
},
|
||||
expected: SegmentProperties{},
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := ExtractServicePropertiesP(test.labels)
|
||||
assert.EqualValues(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsEnabled(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -884,97 +545,6 @@ func TestIsEnabled(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIsEnabledP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels *map[string]string
|
||||
exposedByDefault bool
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
desc: "nil labels map & exposedByDefault true",
|
||||
exposedByDefault: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "nil labels map & exposedByDefault false",
|
||||
exposedByDefault: false,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "exposedByDefault false and label enable true",
|
||||
labels: &map[string]string{
|
||||
TraefikEnable: "true",
|
||||
},
|
||||
exposedByDefault: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "exposedByDefault false and label enable false",
|
||||
labels: &map[string]string{
|
||||
TraefikEnable: "false",
|
||||
},
|
||||
exposedByDefault: false,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "exposedByDefault true and label enable false",
|
||||
labels: &map[string]string{
|
||||
TraefikEnable: "false",
|
||||
},
|
||||
exposedByDefault: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "exposedByDefault true and label enable true",
|
||||
labels: &map[string]string{
|
||||
TraefikEnable: "true",
|
||||
},
|
||||
exposedByDefault: true,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := IsEnabledP(test.labels, test.exposedByDefault)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServiceLabel(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labelName string
|
||||
serviceName string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "without service name",
|
||||
labelName: TraefikPort,
|
||||
expected: TraefikPort,
|
||||
},
|
||||
{
|
||||
desc: "with service name",
|
||||
labelName: TraefikPort,
|
||||
serviceName: "bar",
|
||||
expected: "traefik.bar.port",
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := GetServiceLabel(test.labelName, test.serviceName)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasPrefix(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -1023,205 +593,100 @@ func TestHasPrefix(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestParseErrorPages(t *testing.T) {
|
||||
func TestGetFuncString(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected map[string]*types.ErrorPage
|
||||
labels map[string]string
|
||||
labelName string
|
||||
defaultValue string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "2 errors pages",
|
||||
labels: map[string]string{
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageStatus: "404",
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageBackend: "foo_backend",
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageQuery: "foo_query",
|
||||
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageStatus: "500,600",
|
||||
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageBackend: "bar_backend",
|
||||
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageQuery: "bar_query",
|
||||
},
|
||||
expected: map[string]*types.ErrorPage{
|
||||
"foo": {
|
||||
Status: []string{"404"},
|
||||
Query: "foo_query",
|
||||
Backend: "foo_backend",
|
||||
},
|
||||
"bar": {
|
||||
Status: []string{"500", "600"},
|
||||
Query: "bar_query",
|
||||
Backend: "bar_backend",
|
||||
},
|
||||
},
|
||||
labels: nil,
|
||||
labelName: TraefikWeight,
|
||||
defaultValue: DefaultWeight,
|
||||
expected: "0",
|
||||
},
|
||||
{
|
||||
desc: "only status field",
|
||||
labels: map[string]string{
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageStatus: "404",
|
||||
TraefikWeight: "10",
|
||||
},
|
||||
expected: map[string]*types.ErrorPage{
|
||||
"foo": {
|
||||
Status: []string{"404"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "invalid field",
|
||||
labels: map[string]string{
|
||||
Prefix + BaseFrontendErrorPage + "foo." + "courgette": "404",
|
||||
},
|
||||
expected: map[string]*types.ErrorPage{"foo": {}},
|
||||
},
|
||||
{
|
||||
desc: "no error pages labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
labelName: TraefikWeight,
|
||||
defaultValue: DefaultWeight,
|
||||
expected: "10",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
for containerID, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Run(test.labelName+strconv.Itoa(containerID), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pages := ParseErrorPages(test.labels, Prefix+BaseFrontendErrorPage, RegexpFrontendErrorPage)
|
||||
|
||||
assert.EqualValues(t, test.expected, pages)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRateSets(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected map[string]*types.Rate
|
||||
}{
|
||||
{
|
||||
desc: "2 rate limits",
|
||||
labels: map[string]string{
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitPeriod: "6",
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitAverage: "12",
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitBurst: "18",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitPeriod: "3",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitAverage: "6",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitBurst: "9",
|
||||
},
|
||||
expected: map[string]*types.Rate{
|
||||
"foo": {
|
||||
Period: flaeg.Duration(6 * time.Second),
|
||||
Average: 12,
|
||||
Burst: 18,
|
||||
},
|
||||
"bar": {
|
||||
Period: flaeg.Duration(3 * time.Second),
|
||||
Average: 6,
|
||||
Burst: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
desc: "no rate limits labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rateSets := ParseRateSets(test.labels, Prefix+BaseFrontendRateLimit, RegexpFrontendRateLimit)
|
||||
|
||||
assert.EqualValues(t, test.expected, rateSets)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractTraefikLabels(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
prefix string
|
||||
originLabels map[string]string
|
||||
expected SegmentProperties
|
||||
}{
|
||||
{
|
||||
desc: "nil labels map",
|
||||
prefix: "traefik",
|
||||
originLabels: nil,
|
||||
expected: SegmentProperties{"": {}},
|
||||
},
|
||||
{
|
||||
desc: "container labels",
|
||||
prefix: "traefik",
|
||||
originLabels: map[string]string{
|
||||
"frontend.priority": "foo", // missing prefix: skip
|
||||
"traefik.port": "bar",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"": {
|
||||
"traefik.port": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "segment labels: only segment no default",
|
||||
prefix: "traefik",
|
||||
originLabels: map[string]string{
|
||||
"traefik.goo.frontend.priority": "A",
|
||||
"traefik.goo.port": "D",
|
||||
"traefik.port": "C",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"goo": {
|
||||
"traefik.frontend.priority": "A",
|
||||
"traefik.port": "D",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "segment labels: use default",
|
||||
prefix: "traefik",
|
||||
originLabels: map[string]string{
|
||||
"traefik.guu.frontend.priority": "B",
|
||||
"traefik.port": "C",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"guu": {
|
||||
"traefik.frontend.priority": "B",
|
||||
"traefik.port": "C",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "segment labels: several segments",
|
||||
prefix: "traefik",
|
||||
originLabels: map[string]string{
|
||||
"traefik.goo.frontend.priority": "A",
|
||||
"traefik.goo.port": "D",
|
||||
"traefik.guu.frontend.priority": "B",
|
||||
"traefik.port": "C",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"goo": {
|
||||
"traefik.frontend.priority": "A",
|
||||
"traefik.port": "D",
|
||||
},
|
||||
"guu": {
|
||||
"traefik.frontend.priority": "B",
|
||||
"traefik.port": "C",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := ExtractTraefikLabels(test.originLabels)
|
||||
actual := GetFuncString(test.labelName, test.defaultValue)(test.labels)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSliceString(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
labelName string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
desc: "no whitelist-label",
|
||||
labels: nil,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "whitelist-label with empty string",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendWhiteListSourceRange: "",
|
||||
},
|
||||
labelName: TraefikFrontendWhiteListSourceRange,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "whitelist-label with IPv4 mask",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendWhiteListSourceRange: "1.2.3.4/16",
|
||||
},
|
||||
labelName: TraefikFrontendWhiteListSourceRange,
|
||||
expected: []string{
|
||||
"1.2.3.4/16",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "whitelist-label with IPv6 mask",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendWhiteListSourceRange: "fe80::/16",
|
||||
},
|
||||
labelName: TraefikFrontendWhiteListSourceRange,
|
||||
expected: []string{
|
||||
"fe80::/16",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "whitelist-label with multiple masks",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendWhiteListSourceRange: "1.1.1.1/24, 1234:abcd::42/32",
|
||||
},
|
||||
labelName: TraefikFrontendWhiteListSourceRange,
|
||||
expected: []string{
|
||||
"1.1.1.1/24",
|
||||
"1234:abcd::42/32",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := GetFuncSliceString(test.labelName)(test.labels)
|
||||
assert.EqualValues(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
301
provider/label/partial.go
Normal file
301
provider/label/partial.go
Normal file
|
@ -0,0 +1,301 @@
|
|||
package label
|
||||
|
||||
import (
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/flaeg"
|
||||
"github.com/containous/traefik/log"
|
||||
"github.com/containous/traefik/types"
|
||||
)
|
||||
|
||||
// GetWhiteList Create white list from labels
|
||||
func GetWhiteList(labels map[string]string) *types.WhiteList {
|
||||
if Has(labels, TraefikFrontendWhitelistSourceRange) {
|
||||
log.Warnf("Deprecated configuration found: %s. Please use %s.", TraefikFrontendWhitelistSourceRange, TraefikFrontendWhiteListSourceRange)
|
||||
}
|
||||
|
||||
ranges := GetSliceStringValue(labels, TraefikFrontendWhiteListSourceRange)
|
||||
if len(ranges) > 0 {
|
||||
return &types.WhiteList{
|
||||
SourceRange: ranges,
|
||||
UseXForwardedFor: GetBoolValue(labels, TraefikFrontendWhiteListUseXForwardedFor, false),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Deprecated
|
||||
values := GetSliceStringValue(labels, TraefikFrontendWhitelistSourceRange)
|
||||
if len(values) > 0 {
|
||||
return &types.WhiteList{
|
||||
SourceRange: values,
|
||||
UseXForwardedFor: false,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRedirect Create redirect from labels
|
||||
func GetRedirect(labels map[string]string) *types.Redirect {
|
||||
permanent := GetBoolValue(labels, TraefikFrontendRedirectPermanent, false)
|
||||
|
||||
if Has(labels, TraefikFrontendRedirectEntryPoint) {
|
||||
return &types.Redirect{
|
||||
EntryPoint: GetStringValue(labels, TraefikFrontendRedirectEntryPoint, ""),
|
||||
Permanent: permanent,
|
||||
}
|
||||
}
|
||||
|
||||
if Has(labels, TraefikFrontendRedirectRegex) &&
|
||||
Has(labels, TraefikFrontendRedirectReplacement) {
|
||||
return &types.Redirect{
|
||||
Regex: GetStringValue(labels, TraefikFrontendRedirectRegex, ""),
|
||||
Replacement: GetStringValue(labels, TraefikFrontendRedirectReplacement, ""),
|
||||
Permanent: permanent,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetErrorPages Create error pages from labels
|
||||
func GetErrorPages(labels map[string]string) map[string]*types.ErrorPage {
|
||||
prefix := Prefix + BaseFrontendErrorPage
|
||||
return ParseErrorPages(labels, prefix, RegexpFrontendErrorPage)
|
||||
}
|
||||
|
||||
// ParseErrorPages parse error pages to create ErrorPage struct
|
||||
func ParseErrorPages(labels map[string]string, labelPrefix string, labelRegex *regexp.Regexp) map[string]*types.ErrorPage {
|
||||
var errorPages map[string]*types.ErrorPage
|
||||
|
||||
for lblName, value := range labels {
|
||||
if strings.HasPrefix(lblName, labelPrefix) {
|
||||
submatch := labelRegex.FindStringSubmatch(lblName)
|
||||
if len(submatch) != 3 {
|
||||
log.Errorf("Invalid page error label: %s, sub-match: %v", lblName, submatch)
|
||||
continue
|
||||
}
|
||||
|
||||
if errorPages == nil {
|
||||
errorPages = make(map[string]*types.ErrorPage)
|
||||
}
|
||||
|
||||
pageName := submatch[1]
|
||||
|
||||
ep, ok := errorPages[pageName]
|
||||
if !ok {
|
||||
ep = &types.ErrorPage{}
|
||||
errorPages[pageName] = ep
|
||||
}
|
||||
|
||||
switch submatch[2] {
|
||||
case SuffixErrorPageStatus:
|
||||
ep.Status = SplitAndTrimString(value, ",")
|
||||
case SuffixErrorPageQuery:
|
||||
ep.Query = value
|
||||
case SuffixErrorPageBackend:
|
||||
ep.Backend = value
|
||||
default:
|
||||
log.Errorf("Invalid page error label: %s", lblName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errorPages
|
||||
}
|
||||
|
||||
// GetRateLimit Create rate limits from labels
|
||||
func GetRateLimit(labels map[string]string) *types.RateLimit {
|
||||
extractorFunc := GetStringValue(labels, TraefikFrontendRateLimitExtractorFunc, "")
|
||||
if len(extractorFunc) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
prefix := Prefix + BaseFrontendRateLimit
|
||||
limits := ParseRateSets(labels, prefix, RegexpFrontendRateLimit)
|
||||
|
||||
return &types.RateLimit{
|
||||
ExtractorFunc: extractorFunc,
|
||||
RateSet: limits,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseRateSets parse rate limits to create Rate struct
|
||||
func ParseRateSets(labels map[string]string, labelPrefix string, labelRegex *regexp.Regexp) map[string]*types.Rate {
|
||||
var rateSets map[string]*types.Rate
|
||||
|
||||
for lblName, rawValue := range labels {
|
||||
if strings.HasPrefix(lblName, labelPrefix) && len(rawValue) > 0 {
|
||||
submatch := labelRegex.FindStringSubmatch(lblName)
|
||||
if len(submatch) != 3 {
|
||||
log.Errorf("Invalid rate limit label: %s, sub-match: %v", lblName, submatch)
|
||||
continue
|
||||
}
|
||||
|
||||
if rateSets == nil {
|
||||
rateSets = make(map[string]*types.Rate)
|
||||
}
|
||||
|
||||
limitName := submatch[1]
|
||||
|
||||
ep, ok := rateSets[limitName]
|
||||
if !ok {
|
||||
ep = &types.Rate{}
|
||||
rateSets[limitName] = ep
|
||||
}
|
||||
|
||||
switch submatch[2] {
|
||||
case "period":
|
||||
var d flaeg.Duration
|
||||
err := d.Set(rawValue)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to parse %q: %q. %v", lblName, rawValue, err)
|
||||
continue
|
||||
}
|
||||
ep.Period = d
|
||||
case "average":
|
||||
value, err := strconv.ParseInt(rawValue, 10, 64)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to parse %q: %q. %v", lblName, rawValue, err)
|
||||
continue
|
||||
}
|
||||
ep.Average = value
|
||||
case "burst":
|
||||
value, err := strconv.ParseInt(rawValue, 10, 64)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to parse %q: %q. %v", lblName, rawValue, err)
|
||||
continue
|
||||
}
|
||||
ep.Burst = value
|
||||
default:
|
||||
log.Errorf("Invalid rate limit label: %s", lblName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return rateSets
|
||||
}
|
||||
|
||||
// GetHeaders Create headers from labels
|
||||
func GetHeaders(labels map[string]string) *types.Headers {
|
||||
headers := &types.Headers{
|
||||
CustomRequestHeaders: GetMapValue(labels, TraefikFrontendRequestHeaders),
|
||||
CustomResponseHeaders: GetMapValue(labels, TraefikFrontendResponseHeaders),
|
||||
SSLProxyHeaders: GetMapValue(labels, TraefikFrontendSSLProxyHeaders),
|
||||
AllowedHosts: GetSliceStringValue(labels, TraefikFrontendAllowedHosts),
|
||||
HostsProxyHeaders: GetSliceStringValue(labels, TraefikFrontendHostsProxyHeaders),
|
||||
STSSeconds: GetInt64Value(labels, TraefikFrontendSTSSeconds, 0),
|
||||
SSLRedirect: GetBoolValue(labels, TraefikFrontendSSLRedirect, false),
|
||||
SSLTemporaryRedirect: GetBoolValue(labels, TraefikFrontendSSLTemporaryRedirect, false),
|
||||
STSIncludeSubdomains: GetBoolValue(labels, TraefikFrontendSTSIncludeSubdomains, false),
|
||||
STSPreload: GetBoolValue(labels, TraefikFrontendSTSPreload, false),
|
||||
ForceSTSHeader: GetBoolValue(labels, TraefikFrontendForceSTSHeader, false),
|
||||
FrameDeny: GetBoolValue(labels, TraefikFrontendFrameDeny, false),
|
||||
ContentTypeNosniff: GetBoolValue(labels, TraefikFrontendContentTypeNosniff, false),
|
||||
BrowserXSSFilter: GetBoolValue(labels, TraefikFrontendBrowserXSSFilter, false),
|
||||
IsDevelopment: GetBoolValue(labels, TraefikFrontendIsDevelopment, false),
|
||||
SSLHost: GetStringValue(labels, TraefikFrontendSSLHost, ""),
|
||||
CustomFrameOptionsValue: GetStringValue(labels, TraefikFrontendCustomFrameOptionsValue, ""),
|
||||
ContentSecurityPolicy: GetStringValue(labels, TraefikFrontendContentSecurityPolicy, ""),
|
||||
PublicKey: GetStringValue(labels, TraefikFrontendPublicKey, ""),
|
||||
ReferrerPolicy: GetStringValue(labels, TraefikFrontendReferrerPolicy, ""),
|
||||
CustomBrowserXSSValue: GetStringValue(labels, TraefikFrontendCustomBrowserXSSValue, ""),
|
||||
}
|
||||
|
||||
if !headers.HasSecureHeadersDefined() && !headers.HasCustomHeadersDefined() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
// GetMaxConn Create max connection from labels
|
||||
func GetMaxConn(labels map[string]string) *types.MaxConn {
|
||||
amount := GetInt64Value(labels, TraefikBackendMaxConnAmount, math.MinInt64)
|
||||
extractorFunc := GetStringValue(labels, TraefikBackendMaxConnExtractorFunc, DefaultBackendMaxconnExtractorFunc)
|
||||
|
||||
if amount == math.MinInt64 || len(extractorFunc) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &types.MaxConn{
|
||||
Amount: amount,
|
||||
ExtractorFunc: extractorFunc,
|
||||
}
|
||||
}
|
||||
|
||||
// GetHealthCheck Create health check from labels
|
||||
func GetHealthCheck(labels map[string]string) *types.HealthCheck {
|
||||
path := GetStringValue(labels, TraefikBackendHealthCheckPath, "")
|
||||
if len(path) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
port := GetIntValue(labels, TraefikBackendHealthCheckPort, DefaultBackendHealthCheckPort)
|
||||
interval := GetStringValue(labels, TraefikBackendHealthCheckInterval, "")
|
||||
|
||||
return &types.HealthCheck{
|
||||
Path: path,
|
||||
Port: port,
|
||||
Interval: interval,
|
||||
}
|
||||
}
|
||||
|
||||
// GetBuffering Create buffering from labels
|
||||
func GetBuffering(labels map[string]string) *types.Buffering {
|
||||
if !HasPrefix(labels, TraefikBackendBuffering) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &types.Buffering{
|
||||
MaxRequestBodyBytes: GetInt64Value(labels, TraefikBackendBufferingMaxRequestBodyBytes, 0),
|
||||
MaxResponseBodyBytes: GetInt64Value(labels, TraefikBackendBufferingMaxResponseBodyBytes, 0),
|
||||
MemRequestBodyBytes: GetInt64Value(labels, TraefikBackendBufferingMemRequestBodyBytes, 0),
|
||||
MemResponseBodyBytes: GetInt64Value(labels, TraefikBackendBufferingMemResponseBodyBytes, 0),
|
||||
RetryExpression: GetStringValue(labels, TraefikBackendBufferingRetryExpression, ""),
|
||||
}
|
||||
}
|
||||
|
||||
// GetCircuitBreaker Create circuit breaker from labels
|
||||
func GetCircuitBreaker(labels map[string]string) *types.CircuitBreaker {
|
||||
circuitBreaker := GetStringValue(labels, TraefikBackendCircuitBreakerExpression, "")
|
||||
if len(circuitBreaker) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &types.CircuitBreaker{Expression: circuitBreaker}
|
||||
}
|
||||
|
||||
// GetLoadBalancer Create load balancer from labels
|
||||
func GetLoadBalancer(labels map[string]string) *types.LoadBalancer {
|
||||
if !HasPrefix(labels, TraefikBackendLoadBalancer) {
|
||||
return nil
|
||||
}
|
||||
|
||||
method := GetStringValue(labels, TraefikBackendLoadBalancerMethod, DefaultBackendLoadBalancerMethod)
|
||||
|
||||
lb := &types.LoadBalancer{
|
||||
Method: method,
|
||||
Sticky: getSticky(labels),
|
||||
}
|
||||
|
||||
if GetBoolValue(labels, TraefikBackendLoadBalancerStickiness, false) {
|
||||
cookieName := GetStringValue(labels, TraefikBackendLoadBalancerStickinessCookieName, DefaultBackendLoadbalancerStickinessCookieName)
|
||||
lb.Stickiness = &types.Stickiness{CookieName: cookieName}
|
||||
}
|
||||
|
||||
return lb
|
||||
}
|
||||
|
||||
// TODO: Deprecated
|
||||
// replaced by Stickiness
|
||||
// Deprecated
|
||||
func getSticky(labels map[string]string) bool {
|
||||
if Has(labels, TraefikBackendLoadBalancerSticky) {
|
||||
log.Warnf("Deprecated configuration found: %s. Please use %s.", TraefikBackendLoadBalancerSticky, TraefikBackendLoadBalancerStickiness)
|
||||
}
|
||||
|
||||
return GetBoolValue(labels, TraefikBackendLoadBalancerSticky, false)
|
||||
}
|
711
provider/label/partial_test.go
Normal file
711
provider/label/partial_test.go
Normal file
|
@ -0,0 +1,711 @@
|
|||
package label
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containous/flaeg"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseErrorPages(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected map[string]*types.ErrorPage
|
||||
}{
|
||||
{
|
||||
desc: "2 errors pages",
|
||||
labels: map[string]string{
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageStatus: "404",
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageBackend: "foo_backend",
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageQuery: "foo_query",
|
||||
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageStatus: "500,600",
|
||||
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageBackend: "bar_backend",
|
||||
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageQuery: "bar_query",
|
||||
},
|
||||
expected: map[string]*types.ErrorPage{
|
||||
"foo": {
|
||||
Status: []string{"404"},
|
||||
Query: "foo_query",
|
||||
Backend: "foo_backend",
|
||||
},
|
||||
"bar": {
|
||||
Status: []string{"500", "600"},
|
||||
Query: "bar_query",
|
||||
Backend: "bar_backend",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "only status field",
|
||||
labels: map[string]string{
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageStatus: "404",
|
||||
},
|
||||
expected: map[string]*types.ErrorPage{
|
||||
"foo": {
|
||||
Status: []string{"404"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "invalid field",
|
||||
labels: map[string]string{
|
||||
Prefix + BaseFrontendErrorPage + "foo." + "courgette": "404",
|
||||
},
|
||||
expected: map[string]*types.ErrorPage{"foo": {}},
|
||||
},
|
||||
{
|
||||
desc: "no error pages labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pages := ParseErrorPages(test.labels, Prefix+BaseFrontendErrorPage, RegexpFrontendErrorPage)
|
||||
|
||||
assert.EqualValues(t, test.expected, pages)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRateSets(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected map[string]*types.Rate
|
||||
}{
|
||||
{
|
||||
desc: "2 rate limits",
|
||||
labels: map[string]string{
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitPeriod: "6",
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitAverage: "12",
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitBurst: "18",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitPeriod: "3",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitAverage: "6",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitBurst: "9",
|
||||
},
|
||||
expected: map[string]*types.Rate{
|
||||
"foo": {
|
||||
Period: flaeg.Duration(6 * time.Second),
|
||||
Average: 12,
|
||||
Burst: 18,
|
||||
},
|
||||
"bar": {
|
||||
Period: flaeg.Duration(3 * time.Second),
|
||||
Average: 6,
|
||||
Burst: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "no rate limits labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rateSets := ParseRateSets(test.labels, Prefix+BaseFrontendRateLimit, RegexpFrontendRateLimit)
|
||||
|
||||
assert.EqualValues(t, test.expected, rateSets)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWhiteList(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected *types.WhiteList
|
||||
}{
|
||||
{
|
||||
desc: "should return nil when no white list labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when deprecated label",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendWhitelistSourceRange: "10.10.10.10",
|
||||
},
|
||||
expected: &types.WhiteList{
|
||||
SourceRange: []string{
|
||||
"10.10.10.10",
|
||||
},
|
||||
UseXForwardedFor: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when only range",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendWhiteListSourceRange: "10.10.10.10",
|
||||
},
|
||||
expected: &types.WhiteList{
|
||||
SourceRange: []string{
|
||||
"10.10.10.10",
|
||||
},
|
||||
UseXForwardedFor: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when range and UseXForwardedFor",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendWhiteListSourceRange: "10.10.10.10",
|
||||
TraefikFrontendWhiteListUseXForwardedFor: "true",
|
||||
},
|
||||
expected: &types.WhiteList{
|
||||
SourceRange: []string{
|
||||
"10.10.10.10",
|
||||
},
|
||||
UseXForwardedFor: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when mix deprecated label and new labels",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendWhitelistSourceRange: "20.20.20.20",
|
||||
TraefikFrontendWhiteListSourceRange: "10.10.10.10",
|
||||
TraefikFrontendWhiteListUseXForwardedFor: "true",
|
||||
},
|
||||
expected: &types.WhiteList{
|
||||
SourceRange: []string{
|
||||
"10.10.10.10",
|
||||
},
|
||||
UseXForwardedFor: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return nil when only UseXForwardedFor",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendWhiteListUseXForwardedFor: "true",
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := GetWhiteList(test.labels)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCircuitBreaker(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected *types.CircuitBreaker
|
||||
}{
|
||||
{
|
||||
desc: "should return nil when no CB label",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when CB label is set",
|
||||
labels: map[string]string{
|
||||
TraefikBackendCircuitBreakerExpression: "NetworkErrorRatio() > 0.5",
|
||||
},
|
||||
expected: &types.CircuitBreaker{
|
||||
Expression: "NetworkErrorRatio() > 0.5",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := GetCircuitBreaker(test.labels)
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLoadBalancer(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected *types.LoadBalancer
|
||||
}{
|
||||
{
|
||||
desc: "should return nil when no LB labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when labels are set",
|
||||
labels: map[string]string{
|
||||
TraefikBackendLoadBalancerMethod: "drr",
|
||||
TraefikBackendLoadBalancerSticky: "true",
|
||||
TraefikBackendLoadBalancerStickiness: "true",
|
||||
TraefikBackendLoadBalancerStickinessCookieName: "foo",
|
||||
},
|
||||
expected: &types.LoadBalancer{
|
||||
Method: "drr",
|
||||
Sticky: true,
|
||||
Stickiness: &types.Stickiness{
|
||||
CookieName: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a nil Stickiness when Stickiness is not set",
|
||||
labels: map[string]string{
|
||||
TraefikBackendLoadBalancerMethod: "drr",
|
||||
TraefikBackendLoadBalancerSticky: "true",
|
||||
TraefikBackendLoadBalancerStickinessCookieName: "foo",
|
||||
},
|
||||
expected: &types.LoadBalancer{
|
||||
Method: "drr",
|
||||
Sticky: true,
|
||||
Stickiness: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := GetLoadBalancer(test.labels)
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMaxConn(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected *types.MaxConn
|
||||
}{
|
||||
{
|
||||
desc: "should return nil when no max conn labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return nil when no amount label",
|
||||
labels: map[string]string{
|
||||
TraefikBackendMaxConnExtractorFunc: "client.ip",
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return default when no empty extractorFunc label",
|
||||
labels: map[string]string{
|
||||
TraefikBackendMaxConnExtractorFunc: "",
|
||||
TraefikBackendMaxConnAmount: "666",
|
||||
},
|
||||
expected: &types.MaxConn{
|
||||
ExtractorFunc: "request.host",
|
||||
Amount: 666,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when max conn labels are set",
|
||||
labels: map[string]string{
|
||||
TraefikBackendMaxConnExtractorFunc: "client.ip",
|
||||
TraefikBackendMaxConnAmount: "666",
|
||||
},
|
||||
expected: &types.MaxConn{
|
||||
ExtractorFunc: "client.ip",
|
||||
Amount: 666,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := GetMaxConn(test.labels)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHealthCheck(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected *types.HealthCheck
|
||||
}{
|
||||
{
|
||||
desc: "should return nil when no health check labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return nil when no health check Path label",
|
||||
labels: map[string]string{
|
||||
TraefikBackendHealthCheckPort: "80",
|
||||
TraefikBackendHealthCheckInterval: "6",
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when health check labels are set",
|
||||
labels: map[string]string{
|
||||
TraefikBackendHealthCheckPath: "/health",
|
||||
TraefikBackendHealthCheckPort: "80",
|
||||
TraefikBackendHealthCheckInterval: "6",
|
||||
},
|
||||
expected: &types.HealthCheck{
|
||||
Path: "/health",
|
||||
Port: 80,
|
||||
Interval: "6",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := GetHealthCheck(test.labels)
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBuffering(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected *types.Buffering
|
||||
}{
|
||||
{
|
||||
desc: "should return nil when no buffering labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when buffering labels are set",
|
||||
labels: map[string]string{
|
||||
TraefikBackendBufferingMaxResponseBodyBytes: "10485760",
|
||||
TraefikBackendBufferingMemResponseBodyBytes: "2097152",
|
||||
TraefikBackendBufferingMaxRequestBodyBytes: "10485760",
|
||||
TraefikBackendBufferingMemRequestBodyBytes: "2097152",
|
||||
TraefikBackendBufferingRetryExpression: "IsNetworkError() && Attempts() <= 2",
|
||||
},
|
||||
expected: &types.Buffering{
|
||||
MaxResponseBodyBytes: 10485760,
|
||||
MemResponseBodyBytes: 2097152,
|
||||
MaxRequestBodyBytes: 10485760,
|
||||
MemRequestBodyBytes: 2097152,
|
||||
RetryExpression: "IsNetworkError() && Attempts() <= 2",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := GetBuffering(test.labels)
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRedirect(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected *types.Redirect
|
||||
}{
|
||||
|
||||
{
|
||||
desc: "should return nil when no redirect labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should use only entry point tag when mix regex redirect and entry point redirect",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendRedirectEntryPoint: "https",
|
||||
TraefikFrontendRedirectRegex: "(.*)",
|
||||
TraefikFrontendRedirectReplacement: "$1",
|
||||
},
|
||||
expected: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when entry point redirect label",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendRedirectEntryPoint: "https",
|
||||
},
|
||||
expected: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when entry point redirect label (permanent)",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendRedirectEntryPoint: "https",
|
||||
TraefikFrontendRedirectPermanent: "true",
|
||||
},
|
||||
expected: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
Permanent: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when regex redirect labels",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendRedirectRegex: "(.*)",
|
||||
TraefikFrontendRedirectReplacement: "$1",
|
||||
},
|
||||
expected: &types.Redirect{
|
||||
Regex: "(.*)",
|
||||
Replacement: "$1",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when regex redirect labels (permanent)",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendRedirectRegex: "(.*)",
|
||||
TraefikFrontendRedirectReplacement: "$1",
|
||||
TraefikFrontendRedirectPermanent: "true",
|
||||
},
|
||||
expected: &types.Redirect{
|
||||
Regex: "(.*)",
|
||||
Replacement: "$1",
|
||||
Permanent: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := GetRedirect(test.labels)
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRateLimit(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected *types.RateLimit
|
||||
}{
|
||||
{
|
||||
desc: "should return nil when no rate limit labels",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when rate limit labels are defined",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendRateLimitExtractorFunc: "client.ip",
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitPeriod: "6",
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitAverage: "12",
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitBurst: "18",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitPeriod: "3",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitAverage: "6",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitBurst: "9",
|
||||
},
|
||||
expected: &types.RateLimit{
|
||||
ExtractorFunc: "client.ip",
|
||||
RateSet: map[string]*types.Rate{
|
||||
"foo": {
|
||||
Period: flaeg.Duration(6 * time.Second),
|
||||
Average: 12,
|
||||
Burst: 18,
|
||||
},
|
||||
"bar": {
|
||||
Period: flaeg.Duration(3 * time.Second),
|
||||
Average: 6,
|
||||
Burst: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return nil when ExtractorFunc is missing",
|
||||
labels: map[string]string{
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitPeriod: "6",
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitAverage: "12",
|
||||
Prefix + BaseFrontendRateLimit + "foo." + SuffixRateLimitBurst: "18",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitPeriod: "3",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitAverage: "6",
|
||||
Prefix + BaseFrontendRateLimit + "bar." + SuffixRateLimitBurst: "9",
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := GetRateLimit(test.labels)
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHeaders(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected *types.Headers
|
||||
}{
|
||||
{
|
||||
desc: "should return nil when no custom headers options are set",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return a struct when all custom headers options are set",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendRequestHeaders: "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8",
|
||||
TraefikFrontendResponseHeaders: "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8",
|
||||
TraefikFrontendSSLProxyHeaders: "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8",
|
||||
TraefikFrontendAllowedHosts: "foo,bar,bor",
|
||||
TraefikFrontendHostsProxyHeaders: "foo,bar,bor",
|
||||
TraefikFrontendSSLHost: "foo",
|
||||
TraefikFrontendCustomFrameOptionsValue: "foo",
|
||||
TraefikFrontendContentSecurityPolicy: "foo",
|
||||
TraefikFrontendPublicKey: "foo",
|
||||
TraefikFrontendReferrerPolicy: "foo",
|
||||
TraefikFrontendCustomBrowserXSSValue: "foo",
|
||||
TraefikFrontendSTSSeconds: "666",
|
||||
TraefikFrontendSSLRedirect: "true",
|
||||
TraefikFrontendSSLTemporaryRedirect: "true",
|
||||
TraefikFrontendSTSIncludeSubdomains: "true",
|
||||
TraefikFrontendSTSPreload: "true",
|
||||
TraefikFrontendForceSTSHeader: "true",
|
||||
TraefikFrontendFrameDeny: "true",
|
||||
TraefikFrontendContentTypeNosniff: "true",
|
||||
TraefikFrontendBrowserXSSFilter: "true",
|
||||
TraefikFrontendIsDevelopment: "true",
|
||||
},
|
||||
expected: &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",
|
||||
},
|
||||
SSLProxyHeaders: 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"},
|
||||
SSLHost: "foo",
|
||||
CustomFrameOptionsValue: "foo",
|
||||
ContentSecurityPolicy: "foo",
|
||||
PublicKey: "foo",
|
||||
ReferrerPolicy: "foo",
|
||||
CustomBrowserXSSValue: "foo",
|
||||
STSSeconds: 666,
|
||||
SSLRedirect: true,
|
||||
SSLTemporaryRedirect: true,
|
||||
STSIncludeSubdomains: true,
|
||||
STSPreload: true,
|
||||
ForceSTSHeader: true,
|
||||
FrameDeny: true,
|
||||
ContentTypeNosniff: true,
|
||||
BrowserXSSFilter: true,
|
||||
IsDevelopment: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := GetHeaders(test.labels)
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderGetErrorPages(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected map[string]*types.ErrorPage
|
||||
}{
|
||||
{
|
||||
desc: "should return nil when no tags",
|
||||
labels: map[string]string{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "should return a map when tags are present",
|
||||
labels: map[string]string{
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageStatus: "404",
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageBackend: "foo_backend",
|
||||
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageQuery: "foo_query",
|
||||
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageStatus: "500,600",
|
||||
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageBackend: "bar_backend",
|
||||
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageQuery: "bar_query",
|
||||
},
|
||||
expected: map[string]*types.ErrorPage{
|
||||
"foo": {
|
||||
Status: []string{"404"},
|
||||
Query: "foo_query",
|
||||
Backend: "foo_backend",
|
||||
},
|
||||
"bar": {
|
||||
Status: []string{"500", "600"},
|
||||
Query: "bar_query",
|
||||
Backend: "bar_backend",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
result := GetErrorPages(test.labels)
|
||||
|
||||
assert.Equal(t, test.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
221
provider/label/segment_test.go
Normal file
221
provider/label/segment_test.go
Normal file
|
@ -0,0 +1,221 @@
|
|||
package label
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestExtractTraefikLabels(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
prefix string
|
||||
originLabels map[string]string
|
||||
expected SegmentProperties
|
||||
}{
|
||||
{
|
||||
desc: "nil labels map",
|
||||
prefix: "traefik",
|
||||
originLabels: nil,
|
||||
expected: SegmentProperties{"": {}},
|
||||
},
|
||||
{
|
||||
desc: "container labels",
|
||||
prefix: "traefik",
|
||||
originLabels: map[string]string{
|
||||
"frontend.priority": "foo", // missing prefix: skip
|
||||
"traefik.port": "bar",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"": {
|
||||
"traefik.port": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "segment labels: only segment no default",
|
||||
prefix: "traefik",
|
||||
originLabels: map[string]string{
|
||||
"traefik.goo.frontend.priority": "A",
|
||||
"traefik.goo.port": "D",
|
||||
"traefik.port": "C",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"goo": {
|
||||
"traefik.frontend.priority": "A",
|
||||
"traefik.port": "D",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "segment labels: use default",
|
||||
prefix: "traefik",
|
||||
originLabels: map[string]string{
|
||||
"traefik.guu.frontend.priority": "B",
|
||||
"traefik.port": "C",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"guu": {
|
||||
"traefik.frontend.priority": "B",
|
||||
"traefik.port": "C",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "segment labels: several segments",
|
||||
prefix: "traefik",
|
||||
originLabels: map[string]string{
|
||||
"traefik.goo.frontend.priority": "A",
|
||||
"traefik.goo.port": "D",
|
||||
"traefik.guu.frontend.priority": "B",
|
||||
"traefik.port": "C",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"goo": {
|
||||
"traefik.frontend.priority": "A",
|
||||
"traefik.port": "D",
|
||||
},
|
||||
"guu": {
|
||||
"traefik.frontend.priority": "B",
|
||||
"traefik.port": "C",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := ExtractTraefikLabels(test.originLabels)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractServiceProperties(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels map[string]string
|
||||
expected SegmentProperties
|
||||
}{
|
||||
{
|
||||
desc: "empty labels map",
|
||||
expected: SegmentProperties{},
|
||||
},
|
||||
{
|
||||
desc: "valid label names",
|
||||
labels: map[string]string{
|
||||
"traefik.foo.port": "bar",
|
||||
"traefik.foo.frontend.bar": "1bar",
|
||||
"traefik.foo.backend": "3bar",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"foo": SegmentPropertyValues{
|
||||
"port": "bar",
|
||||
"frontend.bar": "1bar",
|
||||
"backend": "3bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "invalid label names",
|
||||
labels: map[string]string{
|
||||
"foo.frontend.bar": "1bar",
|
||||
"traefik.foo.frontend.": "2bar",
|
||||
"traefik.foo.port.bar": "barbar",
|
||||
"traefik.foo.frontend": "0bar",
|
||||
"traefik.frontend.foo.backend": "0bar",
|
||||
},
|
||||
expected: SegmentProperties{},
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := ExtractServiceProperties(test.labels)
|
||||
assert.EqualValues(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractServicePropertiesP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labels *map[string]string
|
||||
expected SegmentProperties
|
||||
}{
|
||||
{
|
||||
desc: "nil labels map",
|
||||
expected: SegmentProperties{},
|
||||
},
|
||||
{
|
||||
desc: "valid label names",
|
||||
labels: &map[string]string{
|
||||
"traefik.foo.port": "bar",
|
||||
"traefik.foo.frontend.bar": "1bar",
|
||||
"traefik.foo.backend": "3bar",
|
||||
},
|
||||
expected: SegmentProperties{
|
||||
"foo": SegmentPropertyValues{
|
||||
"port": "bar",
|
||||
"frontend.bar": "1bar",
|
||||
"backend": "3bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "invalid label names",
|
||||
labels: &map[string]string{
|
||||
"foo.frontend.bar": "1bar",
|
||||
"traefik.foo.frontend.": "2bar",
|
||||
"traefik.foo.port.bar": "barbar",
|
||||
"traefik.foo.frontend": "0bar",
|
||||
"traefik.frontend.foo.backend": "0bar",
|
||||
},
|
||||
expected: SegmentProperties{},
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := ExtractServicePropertiesP(test.labels)
|
||||
assert.EqualValues(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServiceLabel(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
labelName string
|
||||
serviceName string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "without service name",
|
||||
labelName: TraefikPort,
|
||||
expected: TraefikPort,
|
||||
},
|
||||
{
|
||||
desc: "with service name",
|
||||
labelName: TraefikPort,
|
||||
serviceName: "bar",
|
||||
expected: "traefik.bar.port",
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := GetServiceLabel(test.labelName, test.serviceName)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue