refactor(k8s): rewrite configuration system.
This commit is contained in:
parent
cee022b935
commit
04dd63da1c
5 changed files with 128 additions and 214 deletions
|
@ -1,71 +0,0 @@
|
||||||
package kubernetes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/containous/traefik/log"
|
|
||||||
"github.com/containous/traefik/types"
|
|
||||||
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getBoolAnnotation(meta *v1beta1.Ingress, name string, defaultValue bool) bool {
|
|
||||||
annotationValue := defaultValue
|
|
||||||
annotationStringValue, ok := meta.Annotations[name]
|
|
||||||
switch {
|
|
||||||
case !ok:
|
|
||||||
// No op.
|
|
||||||
case annotationStringValue == "false":
|
|
||||||
annotationValue = false
|
|
||||||
case annotationStringValue == "true":
|
|
||||||
annotationValue = true
|
|
||||||
default:
|
|
||||||
log.Warnf("Unknown value %q for %q, falling back to %v", annotationStringValue, name, defaultValue)
|
|
||||||
}
|
|
||||||
return annotationValue
|
|
||||||
}
|
|
||||||
|
|
||||||
func getStringAnnotation(meta *v1beta1.Ingress, name string) string {
|
|
||||||
value := meta.Annotations[name]
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSliceAnnotation(meta *v1beta1.Ingress, name string) []string {
|
|
||||||
var value []string
|
|
||||||
if annotation, ok := meta.Annotations[name]; ok && annotation != "" {
|
|
||||||
value = types.SplitAndTrimString(annotation)
|
|
||||||
}
|
|
||||||
if len(value) == 0 {
|
|
||||||
log.Debugf("Could not load %v annotation, skipping...", name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMapAnnotation(meta *v1beta1.Ingress, annotName string) map[string]string {
|
|
||||||
if values, ok := meta.Annotations[annotName]; ok {
|
|
||||||
|
|
||||||
if len(values) == 0 {
|
|
||||||
log.Errorf("Missing value for annotation %q", annotName)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
mapValue := make(map[string]string)
|
|
||||||
for _, parts := range strings.Split(values, "||") {
|
|
||||||
pair := strings.SplitN(parts, ":", 2)
|
|
||||||
if len(pair) != 2 {
|
|
||||||
log.Warnf("Could not load %q: %v, skipping...", annotName, pair)
|
|
||||||
} else {
|
|
||||||
mapValue[http.CanonicalHeaderKey(strings.TrimSpace(pair[0]))] = strings.TrimSpace(pair[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(mapValue) == 0 {
|
|
||||||
log.Errorf("Could not load %q, skipping...", annotName)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return mapValue
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -213,7 +213,7 @@ func (c *clientImpl) WatchObjects(namespace, kind string, object runtime.Object,
|
||||||
return informer
|
return informer
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadInformer(listWatch *cache.ListWatch, object runtime.Object, watchCh chan<- interface{}) cache.SharedInformer {
|
func loadInformer(listWatch cache.ListerWatcher, object runtime.Object, watchCh chan<- interface{}) cache.SharedInformer {
|
||||||
informer := cache.NewSharedInformer(
|
informer := cache.NewSharedInformer(
|
||||||
listWatch,
|
listWatch,
|
||||||
object,
|
object,
|
||||||
|
|
66
provider/kubernetes/client_mock_test.go
Normal file
66
provider/kubernetes/client_mock_test.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package kubernetes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
|
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type clientMock struct {
|
||||||
|
ingresses []*v1beta1.Ingress
|
||||||
|
services []*v1.Service
|
||||||
|
secrets []*v1.Secret
|
||||||
|
endpoints []*v1.Endpoints
|
||||||
|
watchChan chan interface{}
|
||||||
|
|
||||||
|
apiServiceError error
|
||||||
|
apiSecretError error
|
||||||
|
apiEndpointsError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c clientMock) GetIngresses() []*v1beta1.Ingress {
|
||||||
|
return c.ingresses
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c clientMock) GetService(namespace, name string) (*v1.Service, bool, error) {
|
||||||
|
if c.apiServiceError != nil {
|
||||||
|
return nil, false, c.apiServiceError
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, service := range c.services {
|
||||||
|
if service.Namespace == namespace && service.Name == name {
|
||||||
|
return service, true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c clientMock) GetEndpoints(namespace, name string) (*v1.Endpoints, bool, error) {
|
||||||
|
if c.apiEndpointsError != nil {
|
||||||
|
return nil, false, c.apiEndpointsError
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, endpoints := range c.endpoints {
|
||||||
|
if endpoints.Namespace == namespace && endpoints.Name == name {
|
||||||
|
return endpoints, true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &v1.Endpoints{}, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c clientMock) GetSecret(namespace, name string) (*v1.Secret, bool, error) {
|
||||||
|
if c.apiSecretError != nil {
|
||||||
|
return nil, false, c.apiSecretError
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, secret := range c.secrets {
|
||||||
|
if secret.Namespace == namespace && secret.Name == name {
|
||||||
|
return secret, true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c clientMock) WatchAll(namespaces Namespaces, labelString string, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||||
|
return c.watchChan, nil
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/containous/traefik/job"
|
"github.com/containous/traefik/job"
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
"github.com/containous/traefik/provider"
|
"github.com/containous/traefik/provider"
|
||||||
|
"github.com/containous/traefik/provider/label"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"k8s.io/client-go/pkg/api/v1"
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
|
@ -95,7 +96,10 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
// certain kinds of API errors getting logged into a directory not
|
// certain kinds of API errors getting logged into a directory not
|
||||||
// available in a `FROM scratch` Docker container, causing glog to abort
|
// available in a `FROM scratch` Docker container, causing glog to abort
|
||||||
// hard with an exit code > 0.
|
// hard with an exit code > 0.
|
||||||
flag.Set("logtostderr", "true")
|
err := flag.Set("logtostderr", "true")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
k8sClient, err := p.newK8sClient()
|
k8sClient, err := p.newK8sClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -186,8 +190,8 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
passHostHeader := getBoolAnnotation(i, types.LabelFrontendPassHostHeader, !p.DisablePassHostHeaders)
|
passHostHeader := label.GetBoolValue(i.Annotations, label.TraefikFrontendPassHostHeader, !p.DisablePassHostHeaders)
|
||||||
passTLSCert := getBoolAnnotation(i, types.LabelFrontendPassTLSCert, p.EnablePassTLSCert)
|
passTLSCert := label.GetBoolValue(i.Annotations, label.TraefikFrontendPassTLSCert, p.EnablePassTLSCert)
|
||||||
|
|
||||||
if realm := i.Annotations[annotationKubernetesAuthRealm]; realm != "" && realm != traefikDefaultRealm {
|
if realm := i.Annotations[annotationKubernetesAuthRealm]; realm != "" && realm != traefikDefaultRealm {
|
||||||
log.Errorf("Value for annotation %q on ingress %s/%s invalid: no realm customization supported", annotationKubernetesAuthRealm, i.ObjectMeta.Namespace, i.ObjectMeta.Name)
|
log.Errorf("Value for annotation %q on ingress %s/%s invalid: no realm customization supported", annotationKubernetesAuthRealm, i.ObjectMeta.Namespace, i.ObjectMeta.Name)
|
||||||
|
@ -195,11 +199,11 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
entryPoints := getSliceAnnotation(i, types.LabelFrontendEntryPoints)
|
entryPoints := label.GetSliceStringValue(i.Annotations, label.TraefikFrontendEntryPoints)
|
||||||
|
|
||||||
whitelistSourceRange := getSliceAnnotation(i, annotationKubernetesWhitelistSourceRange)
|
whitelistSourceRange := label.GetSliceStringValue(i.Annotations, annotationKubernetesWhitelistSourceRange)
|
||||||
|
|
||||||
entryPointRedirect, _ := i.Annotations[types.LabelFrontendRedirect]
|
entryPointRedirect := i.Annotations[label.TraefikFrontendRedirect]
|
||||||
|
|
||||||
if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
|
if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
|
||||||
basicAuthCreds, err := handleBasicAuthConfig(i, k8sClient)
|
basicAuthCreds, err := handleBasicAuthConfig(i, k8sClient)
|
||||||
|
@ -208,29 +212,29 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
priority := getPriority(i)
|
priority := label.GetIntValue(i.Annotations, label.TraefikFrontendPriority, 0)
|
||||||
|
|
||||||
headers := types.Headers{
|
headers := types.Headers{
|
||||||
CustomRequestHeaders: getMapAnnotation(i, annotationKubernetesCustomRequestHeaders),
|
CustomRequestHeaders: label.GetMapValue(i.Annotations, annotationKubernetesCustomRequestHeaders),
|
||||||
CustomResponseHeaders: getMapAnnotation(i, annotationKubernetesCustomResponseHeaders),
|
CustomResponseHeaders: label.GetMapValue(i.Annotations, annotationKubernetesCustomResponseHeaders),
|
||||||
AllowedHosts: getSliceAnnotation(i, annotationKubernetesAllowedHosts),
|
AllowedHosts: label.GetSliceStringValue(i.Annotations, annotationKubernetesAllowedHosts),
|
||||||
HostsProxyHeaders: getSliceAnnotation(i, annotationKubernetesProxyHeaders),
|
HostsProxyHeaders: label.GetSliceStringValue(i.Annotations, annotationKubernetesProxyHeaders),
|
||||||
SSLRedirect: getBoolAnnotation(i, annotationKubernetesSSLRedirect, false),
|
SSLRedirect: label.GetBoolValue(i.Annotations, annotationKubernetesSSLRedirect, false),
|
||||||
SSLTemporaryRedirect: getBoolAnnotation(i, annotationKubernetesSSLTemporaryRedirect, false),
|
SSLTemporaryRedirect: label.GetBoolValue(i.Annotations, annotationKubernetesSSLTemporaryRedirect, false),
|
||||||
SSLHost: getStringAnnotation(i, annotationKubernetesSSLHost),
|
SSLHost: label.GetStringValue(i.Annotations, annotationKubernetesSSLHost, ""),
|
||||||
SSLProxyHeaders: getMapAnnotation(i, annotationKubernetesSSLProxyHeaders),
|
SSLProxyHeaders: label.GetMapValue(i.Annotations, annotationKubernetesSSLProxyHeaders),
|
||||||
STSSeconds: getSTSSeconds(i),
|
STSSeconds: label.GetInt64Value(i.Annotations, annotationKubernetesHSTSMaxAge, 0),
|
||||||
STSIncludeSubdomains: getBoolAnnotation(i, annotationKubernetesHSTSIncludeSubdomains, false),
|
STSIncludeSubdomains: label.GetBoolValue(i.Annotations, annotationKubernetesHSTSIncludeSubdomains, false),
|
||||||
STSPreload: getBoolAnnotation(i, annotationKubernetesHSTSPreload, false),
|
STSPreload: label.GetBoolValue(i.Annotations, annotationKubernetesHSTSPreload, false),
|
||||||
ForceSTSHeader: getBoolAnnotation(i, annotationKubernetesForceHSTSHeader, false),
|
ForceSTSHeader: label.GetBoolValue(i.Annotations, annotationKubernetesForceHSTSHeader, false),
|
||||||
FrameDeny: getBoolAnnotation(i, annotationKubernetesFrameDeny, false),
|
FrameDeny: label.GetBoolValue(i.Annotations, annotationKubernetesFrameDeny, false),
|
||||||
CustomFrameOptionsValue: getStringAnnotation(i, annotationKubernetesCustomFrameOptionsValue),
|
CustomFrameOptionsValue: label.GetStringValue(i.Annotations, annotationKubernetesCustomFrameOptionsValue, ""),
|
||||||
ContentTypeNosniff: getBoolAnnotation(i, annotationKubernetesContentTypeNosniff, false),
|
ContentTypeNosniff: label.GetBoolValue(i.Annotations, annotationKubernetesContentTypeNosniff, false),
|
||||||
BrowserXSSFilter: getBoolAnnotation(i, annotationKubernetesBrowserXSSFilter, false),
|
BrowserXSSFilter: label.GetBoolValue(i.Annotations, annotationKubernetesBrowserXSSFilter, false),
|
||||||
ContentSecurityPolicy: getStringAnnotation(i, annotationKubernetesContentSecurityPolicy),
|
ContentSecurityPolicy: label.GetStringValue(i.Annotations, annotationKubernetesContentSecurityPolicy, ""),
|
||||||
PublicKey: getStringAnnotation(i, annotationKubernetesPublicKey),
|
PublicKey: label.GetStringValue(i.Annotations, annotationKubernetesPublicKey, ""),
|
||||||
ReferrerPolicy: getStringAnnotation(i, annotationKubernetesReferrerPolicy),
|
ReferrerPolicy: label.GetStringValue(i.Annotations, annotationKubernetesReferrerPolicy, ""),
|
||||||
IsDevelopment: getBoolAnnotation(i, annotationKubernetesIsDevelopment, false),
|
IsDevelopment: label.GetBoolValue(i.Annotations, annotationKubernetesIsDevelopment, false),
|
||||||
}
|
}
|
||||||
|
|
||||||
templateObjects.Frontends[r.Host+pa.Path] = &types.Frontend{
|
templateObjects.Frontends[r.Host+pa.Path] = &types.Frontend{
|
||||||
|
@ -279,29 +283,29 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if expression := service.Annotations[types.LabelTraefikBackendCircuitbreaker]; expression != "" {
|
if expression := service.Annotations[label.TraefikBackendCircuitBreaker]; expression != "" {
|
||||||
templateObjects.Backends[r.Host+pa.Path].CircuitBreaker = &types.CircuitBreaker{
|
templateObjects.Backends[r.Host+pa.Path].CircuitBreaker = &types.CircuitBreaker{
|
||||||
Expression: expression,
|
Expression: expression,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if service.Annotations[types.LabelBackendLoadbalancerMethod] == "drr" {
|
if service.Annotations[label.TraefikBackendLoadBalancerMethod] == "drr" {
|
||||||
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Method = "drr"
|
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Method = "drr"
|
||||||
}
|
}
|
||||||
|
|
||||||
if sticky := service.Annotations[types.LabelBackendLoadbalancerSticky]; len(sticky) > 0 {
|
if sticky := service.Annotations[label.TraefikBackendLoadBalancerSticky]; len(sticky) > 0 {
|
||||||
log.Warnf("Deprecated configuration found: %s. Please use %s.", types.LabelBackendLoadbalancerSticky, types.LabelBackendLoadbalancerStickiness)
|
log.Warnf("Deprecated configuration found: %s. Please use %s.", label.TraefikBackendLoadBalancerSticky, label.TraefikBackendLoadBalancerStickiness)
|
||||||
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Sticky = strings.EqualFold(strings.TrimSpace(sticky), "true")
|
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Sticky = strings.EqualFold(strings.TrimSpace(sticky), "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
if service.Annotations[types.LabelBackendLoadbalancerStickiness] == "true" {
|
if service.Annotations[label.TraefikBackendLoadBalancerStickiness] == "true" {
|
||||||
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Stickiness = &types.Stickiness{}
|
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Stickiness = &types.Stickiness{}
|
||||||
if cookieName := service.Annotations[types.LabelBackendLoadbalancerStickinessCookieName]; len(cookieName) > 0 {
|
if cookieName := service.Annotations[label.TraefikBackendLoadBalancerStickinessCookieName]; len(cookieName) > 0 {
|
||||||
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Stickiness.CookieName = cookieName
|
templateObjects.Backends[r.Host+pa.Path].LoadBalancer.Stickiness.CookieName = cookieName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol := "http"
|
protocol := label.DefaultProtocol
|
||||||
for _, port := range service.Spec.Ports {
|
for _, port := range service.Spec.Ports {
|
||||||
if equalPorts(port, pa.Backend.ServicePort) {
|
if equalPorts(port, pa.Backend.ServicePort) {
|
||||||
if port.Port == 443 {
|
if port.Port == 443 {
|
||||||
|
@ -365,20 +369,12 @@ func (p *Provider) loadConfig(templateObjects types.Configuration) *types.Config
|
||||||
return configuration
|
return configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSTSSeconds(i *v1beta1.Ingress) int64 {
|
|
||||||
value, err := strconv.ParseInt(i.ObjectMeta.Annotations[annotationKubernetesHSTSMaxAge], 10, 64)
|
|
||||||
if err == nil && value > 0 {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRuleForPath(pa v1beta1.HTTPIngressPath, i *v1beta1.Ingress) string {
|
func getRuleForPath(pa v1beta1.HTTPIngressPath, i *v1beta1.Ingress) string {
|
||||||
if len(pa.Path) == 0 {
|
if len(pa.Path) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleType := i.Annotations[types.LabelFrontendRuleType]
|
ruleType := i.Annotations[label.TraefikFrontendRuleType]
|
||||||
if ruleType == "" {
|
if ruleType == "" {
|
||||||
ruleType = ruleTypePathPrefix
|
ruleType = ruleTypePathPrefix
|
||||||
}
|
}
|
||||||
|
@ -392,39 +388,26 @@ func getRuleForPath(pa v1beta1.HTTPIngressPath, i *v1beta1.Ingress) string {
|
||||||
return strings.Join(rules, ";")
|
return strings.Join(rules, ";")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPriority(i *v1beta1.Ingress) int {
|
|
||||||
priority := 0
|
|
||||||
|
|
||||||
priorityRaw, ok := i.Annotations[types.LabelFrontendPriority]
|
|
||||||
if ok {
|
|
||||||
priorityParsed, err := strconv.Atoi(priorityRaw)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
priority = priorityParsed
|
|
||||||
} else {
|
|
||||||
log.Errorf("Error in ingress: failed to parse %q value %q.", types.LabelFrontendPriority, priorityRaw)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return priority
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleBasicAuthConfig(i *v1beta1.Ingress, k8sClient Client) ([]string, error) {
|
func handleBasicAuthConfig(i *v1beta1.Ingress, k8sClient Client) ([]string, error) {
|
||||||
authType, exists := i.Annotations[annotationKubernetesAuthType]
|
authType, exists := i.Annotations[annotationKubernetesAuthType]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.ToLower(authType) != "basic" {
|
if strings.ToLower(authType) != "basic" {
|
||||||
return nil, fmt.Errorf("unsupported auth-type on annotation ingress.kubernetes.io/auth-type: %q", authType)
|
return nil, fmt.Errorf("unsupported auth-type on annotation ingress.kubernetes.io/auth-type: %q", authType)
|
||||||
}
|
}
|
||||||
|
|
||||||
authSecret := i.Annotations[annotationKubernetesAuthSecret]
|
authSecret := i.Annotations[annotationKubernetesAuthSecret]
|
||||||
if authSecret == "" {
|
if authSecret == "" {
|
||||||
return nil, errors.New("auth-secret annotation ingress.kubernetes.io/auth-secret must be set")
|
return nil, errors.New("auth-secret annotation ingress.kubernetes.io/auth-secret must be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
basicAuthCreds, err := loadAuthCredentials(i.Namespace, authSecret, k8sClient)
|
basicAuthCreds, err := loadAuthCredentials(i.Namespace, authSecret, k8sClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to load auth credentials: %s", err)
|
return nil, fmt.Errorf("failed to load auth credentials: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return basicAuthCreds, nil
|
return basicAuthCreds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,10 +468,5 @@ func equalPorts(servicePort v1.ServicePort, ingressPort intstr.IntOrString) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldProcessIngress(ingressClass string) bool {
|
func shouldProcessIngress(ingressClass string) bool {
|
||||||
switch ingressClass {
|
return ingressClass == "" || ingressClass == "traefik"
|
||||||
case "", "traefik":
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/provider/label"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"k8s.io/client-go/pkg/api/v1"
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
|
@ -372,7 +373,7 @@ func TestRuleType(t *testing.T) {
|
||||||
|
|
||||||
if test.ingressRuleType != "" {
|
if test.ingressRuleType != "" {
|
||||||
ingress.ObjectMeta.Annotations = map[string]string{
|
ingress.ObjectMeta.Annotations = map[string]string{
|
||||||
types.LabelFrontendRuleType: test.ingressRuleType,
|
label.TraefikFrontendRuleType: test.ingressRuleType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,8 +822,8 @@ func TestServiceAnnotations(t *testing.T) {
|
||||||
UID: "1",
|
UID: "1",
|
||||||
Namespace: "testing",
|
Namespace: "testing",
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
types.LabelTraefikBackendCircuitbreaker: "NetworkErrorRatio() > 0.5",
|
label.TraefikBackendCircuitBreaker: "NetworkErrorRatio() > 0.5",
|
||||||
types.LabelBackendLoadbalancerMethod: "drr",
|
label.TraefikBackendLoadBalancerMethod: "drr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1.ServiceSpec{
|
Spec: v1.ServiceSpec{
|
||||||
|
@ -840,8 +841,8 @@ func TestServiceAnnotations(t *testing.T) {
|
||||||
UID: "2",
|
UID: "2",
|
||||||
Namespace: "testing",
|
Namespace: "testing",
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
types.LabelTraefikBackendCircuitbreaker: "",
|
label.TraefikBackendCircuitBreaker: "",
|
||||||
types.LabelBackendLoadbalancerSticky: "true",
|
label.TraefikBackendLoadBalancerSticky: "true",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1.ServiceSpec{
|
Spec: v1.ServiceSpec{
|
||||||
|
@ -1009,7 +1010,7 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Namespace: "testing",
|
Namespace: "testing",
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
types.LabelFrontendPassHostHeader: "false",
|
label.TraefikFrontendPassHostHeader: "false",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1beta1.IngressSpec{
|
Spec: v1beta1.IngressSpec{
|
||||||
|
@ -1037,8 +1038,8 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Namespace: "testing",
|
Namespace: "testing",
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
"kubernetes.io/ingress.class": "traefik",
|
"kubernetes.io/ingress.class": "traefik",
|
||||||
types.LabelFrontendPassHostHeader: "true",
|
label.TraefikFrontendPassHostHeader: "true",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1beta1.IngressSpec{
|
Spec: v1beta1.IngressSpec{
|
||||||
|
@ -1066,8 +1067,8 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Namespace: "testing",
|
Namespace: "testing",
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
"kubernetes.io/ingress.class": "traefik",
|
"kubernetes.io/ingress.class": "traefik",
|
||||||
types.LabelFrontendPassTLSCert: "true",
|
label.TraefikFrontendPassTLSCert: "true",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1beta1.IngressSpec{
|
Spec: v1beta1.IngressSpec{
|
||||||
|
@ -1095,8 +1096,8 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Namespace: "testing",
|
Namespace: "testing",
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
"kubernetes.io/ingress.class": "traefik",
|
"kubernetes.io/ingress.class": "traefik",
|
||||||
types.LabelFrontendEntryPoints: "http,https",
|
label.TraefikFrontendEntryPoints: "http,https",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1beta1.IngressSpec{
|
Spec: v1beta1.IngressSpec{
|
||||||
|
@ -1267,7 +1268,7 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
Namespace: "testing",
|
Namespace: "testing",
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
"kubernetes.io/ingress.class": "traefik",
|
"kubernetes.io/ingress.class": "traefik",
|
||||||
types.LabelFrontendRedirect: "https",
|
label.TraefikFrontendRedirect: "https",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1beta1.IngressSpec{
|
Spec: v1beta1.IngressSpec{
|
||||||
|
@ -1563,7 +1564,7 @@ func TestPriorityHeaderValue(t *testing.T) {
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Namespace: "testing",
|
Namespace: "testing",
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
types.LabelFrontendPriority: "1337",
|
label.TraefikFrontendPriority: "1337",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1beta1.IngressSpec{
|
Spec: v1beta1.IngressSpec{
|
||||||
|
@ -1664,7 +1665,7 @@ func TestInvalidPassTLSCertValue(t *testing.T) {
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Namespace: "testing",
|
Namespace: "testing",
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
types.LabelFrontendPassTLSCert: "herpderp",
|
label.TraefikFrontendPassTLSCert: "herpderp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1beta1.IngressSpec{
|
Spec: v1beta1.IngressSpec{
|
||||||
|
@ -1765,7 +1766,7 @@ func TestInvalidPassHostHeaderValue(t *testing.T) {
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Namespace: "testing",
|
Namespace: "testing",
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
types.LabelFrontendPassHostHeader: "herpderp",
|
label.TraefikFrontendPassHostHeader: "herpderp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1beta1.IngressSpec{
|
Spec: v1beta1.IngressSpec{
|
||||||
|
@ -2261,63 +2262,3 @@ func TestBasicAuthInTemplate(t *testing.T) {
|
||||||
t.Fatalf("unexpected credentials: %+v", got)
|
t.Fatalf("unexpected credentials: %+v", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type clientMock struct {
|
|
||||||
ingresses []*v1beta1.Ingress
|
|
||||||
services []*v1.Service
|
|
||||||
secrets []*v1.Secret
|
|
||||||
endpoints []*v1.Endpoints
|
|
||||||
watchChan chan interface{}
|
|
||||||
|
|
||||||
apiServiceError error
|
|
||||||
apiSecretError error
|
|
||||||
apiEndpointsError error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c clientMock) GetIngresses() []*v1beta1.Ingress {
|
|
||||||
return c.ingresses
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c clientMock) GetService(namespace, name string) (*v1.Service, bool, error) {
|
|
||||||
if c.apiServiceError != nil {
|
|
||||||
return nil, false, c.apiServiceError
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, service := range c.services {
|
|
||||||
if service.Namespace == namespace && service.Name == name {
|
|
||||||
return service, true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c clientMock) GetEndpoints(namespace, name string) (*v1.Endpoints, bool, error) {
|
|
||||||
if c.apiEndpointsError != nil {
|
|
||||||
return nil, false, c.apiEndpointsError
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, endpoints := range c.endpoints {
|
|
||||||
if endpoints.Namespace == namespace && endpoints.Name == name {
|
|
||||||
return endpoints, true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &v1.Endpoints{}, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c clientMock) GetSecret(namespace, name string) (*v1.Secret, bool, error) {
|
|
||||||
if c.apiSecretError != nil {
|
|
||||||
return nil, false, c.apiSecretError
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, secret := range c.secrets {
|
|
||||||
if secret.Namespace == namespace && secret.Name == name {
|
|
||||||
return secret, true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c clientMock) WatchAll(namespaces Namespaces, labelString string, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
|
||||||
return c.watchChan, nil
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue