2017-04-17 10:50:02 +00:00
package kubernetes
2016-04-20 11:26:51 +00:00
import (
2017-03-17 15:34:34 +00:00
"errors"
2017-02-06 23:04:30 +00:00
"fmt"
2018-06-19 20:10:03 +00:00
"os"
2018-07-06 08:06:04 +00:00
"strings"
2016-04-20 11:26:51 +00:00
"testing"
2017-12-21 21:07:37 +00:00
"time"
2016-11-11 22:50:20 +00:00
2017-12-02 18:28:11 +00:00
"github.com/containous/traefik/provider/label"
2018-01-07 23:36:03 +00:00
"github.com/containous/traefik/tls"
2018-01-02 17:03:50 +00:00
"github.com/containous/traefik/types"
2017-07-07 19:27:54 +00:00
"github.com/stretchr/testify/assert"
2017-12-05 19:24:03 +00:00
"github.com/stretchr/testify/require"
2018-02-14 08:56:04 +00:00
corev1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
2016-04-20 11:26:51 +00:00
)
func TestLoadIngresses ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress (
iNamespace ( "testing" ) ,
iRules (
iRule ( iHost ( "foo" ) ,
iPaths (
onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ,
onePath ( iPath ( "/namedthing" ) , iBackend ( "service4" , intstr . FromString ( "https" ) ) ) ) ,
) ,
iRule ( iHost ( "bar" ) ,
iPaths (
onePath ( iBackend ( "service3" , intstr . FromString ( "https" ) ) ) ,
2018-06-19 20:10:03 +00:00
onePath ( iBackend ( "service2" , intstr . FromInt ( 802 ) ) ) ,
) ,
) ,
iRule ( iHost ( "service5" ) ,
iPaths (
onePath ( iBackend ( "service5" , intstr . FromInt ( 8888 ) ) ) ,
) ,
) ,
iRule ( iHost ( "service6" ) ,
iPaths (
onePath ( iBackend ( "service6" , intstr . FromInt ( 80 ) ) ) ,
) ,
2017-12-05 19:24:03 +00:00
) ,
) ,
) ,
}
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
buildService (
sName ( "service2" ) ,
sNamespace ( "testing" ) ,
sUID ( "2" ) ,
sSpec (
clusterIP ( "10.0.0.2" ) ,
sPorts ( sPort ( 802 , "" ) ) ) ,
) ,
buildService (
sName ( "service3" ) ,
sNamespace ( "testing" ) ,
sUID ( "3" ) ,
sSpec (
clusterIP ( "10.0.0.3" ) ,
sPorts (
sPort ( 80 , "http" ) ,
sPort ( 443 , "https" ) ) ,
) ,
) ,
buildService (
sName ( "service4" ) ,
sNamespace ( "testing" ) ,
sUID ( "4" ) ,
sSpec (
clusterIP ( "10.0.0.4" ) ,
sType ( "ExternalName" ) ,
sExternalName ( "example.com" ) ,
sPorts ( sPort ( 443 , "https" ) ) ) ,
) ,
2018-06-19 20:10:03 +00:00
buildService (
sName ( "service5" ) ,
sNamespace ( "testing" ) ,
sUID ( "5" ) ,
sSpec (
clusterIP ( "10.0.0.5" ) ,
sType ( "ExternalName" ) ,
sExternalName ( "example.com" ) ,
sPorts ( sPort ( 8888 , "http" ) ) ) ,
) ,
buildService (
sName ( "service6" ) ,
sNamespace ( "testing" ) ,
sUID ( "6" ) ,
sSpec (
clusterIP ( "10.0.0.6" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
2016-04-20 11:26:51 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
endpoints := [ ] * corev1 . Endpoints {
2017-12-05 19:24:03 +00:00
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service1" ) ,
eUID ( "1" ) ,
subset (
eAddresses ( eAddress ( "10.10.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
subset (
eAddresses ( eAddress ( "10.21.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
) ,
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service3" ) ,
eUID ( "3" ) ,
subset (
eAddresses ( eAddress ( "10.15.0.1" ) ) ,
ePorts (
ePort ( 8080 , "http" ) ,
ePort ( 8443 , "https" ) ) ,
) ,
subset (
eAddresses ( eAddress ( "10.15.0.2" ) ) ,
ePorts (
ePort ( 9080 , "http" ) ,
ePort ( 9443 , "https" ) ) ,
) ,
) ,
2018-06-19 20:10:03 +00:00
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service6" ) ,
eUID ( "6" ) ,
subset (
eAddresses ( eAddressWithTargetRef ( "http://10.15.0.3:80" , "10.15.0.3" ) ) ,
ePorts ( ePort ( 80 , "" ) ) ) ,
) ,
2016-05-20 16:34:57 +00:00
}
2017-12-05 19:24:03 +00:00
2016-04-20 11:26:51 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
2016-05-20 16:34:57 +00:00
endpoints : endpoints ,
2016-04-20 11:26:51 +00:00
watchChan : watchChan ,
}
2017-04-17 10:50:02 +00:00
provider := Provider { }
2017-12-05 19:24:03 +00:00
2016-04-20 11:26:51 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2016-04-20 11:26:51 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends (
backend ( "foo/bar" ,
lbMethod ( "wrr" ) ,
servers (
server ( "http://10.10.0.1:8080" , weight ( 1 ) ) ,
server ( "http://10.21.0.1:8080" , weight ( 1 ) ) ) ,
) ,
backend ( "foo/namedthing" ,
lbMethod ( "wrr" ) ,
2018-06-19 20:10:03 +00:00
servers (
server ( "https://example.com" , weight ( 1 ) ) ,
) ,
2017-12-05 19:24:03 +00:00
) ,
backend ( "bar" ,
lbMethod ( "wrr" ) ,
servers (
server ( "https://10.15.0.1:8443" , weight ( 1 ) ) ,
2018-06-19 20:10:03 +00:00
server ( "https://10.15.0.2:9443" , weight ( 1 ) ) ,
) ,
) ,
backend ( "service5" ,
lbMethod ( "wrr" ) ,
servers (
server ( "http://example.com:8888" , weight ( 1 ) ) ,
) ,
) ,
backend ( "service6" ,
lbMethod ( "wrr" ) ,
servers (
server ( "http://10.15.0.3:80" , weight ( 1 ) ) ,
) ,
2017-12-05 19:24:03 +00:00
) ,
) ,
frontends (
frontend ( "foo/bar" ,
passHostHeader ( ) ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
frontend ( "foo/namedthing" ,
passHostHeader ( ) ,
routes (
route ( "/namedthing" , "PathPrefix:/namedthing" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
frontend ( "bar" ,
passHostHeader ( ) ,
routes ( route ( "bar" , "Host:bar" ) ) ,
) ,
2018-06-19 20:10:03 +00:00
frontend ( "service5" ,
passHostHeader ( ) ,
routes ( route ( "service5" , "Host:service5" ) ) ,
) ,
frontend ( "service6" ,
passHostHeader ( ) ,
routes ( route ( "service6" , "Host:service6" ) ) ,
) ,
2017-12-05 19:24:03 +00:00
) ,
)
2017-08-18 14:14:03 +00:00
assert . Equal ( t , expected , actual )
2016-04-20 11:26:51 +00:00
}
2018-07-03 16:58:03 +00:00
func TestLoadGlobalIngressWithPortNumbers ( t * testing . T ) {
ingresses := [ ] * extensionsv1beta1 . Ingress {
buildIngress (
iNamespace ( "testing" ) ,
iSpecBackends ( iSpecBackend ( iIngressBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ,
) ,
}
services := [ ] * corev1 . Service {
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
}
endpoints := [ ] * corev1 . Endpoints {
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service1" ) ,
eUID ( "1" ) ,
subset (
eAddresses ( eAddress ( "10.10.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
) ,
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
watchChan : watchChan ,
}
provider := Provider { }
actual , err := provider . loadIngresses ( client )
require . NoError ( t , err , "error loading ingresses" )
expected := buildConfiguration (
backends (
backend ( "global-default-backend" ,
lbMethod ( "wrr" ) ,
servers (
server ( "http://10.10.0.1:8080" , weight ( 1 ) ) ,
) ,
) ,
) ,
frontends (
frontend ( "global-default-backend" ,
frontendName ( "global-default-frontend" ) ,
passHostHeader ( ) ,
routes (
route ( "/" , "PathPrefix:/" ) ,
) ,
) ,
) ,
)
assert . Equal ( t , expected , actual )
}
func TestLoadGlobalIngressWithHttpsPortNames ( t * testing . T ) {
ingresses := [ ] * extensionsv1beta1 . Ingress {
buildIngress (
iNamespace ( "testing" ) ,
iSpecBackends ( iSpecBackend ( iIngressBackend ( "service1" , intstr . FromString ( "https-global" ) ) ) ) ,
) ,
}
services := [ ] * corev1 . Service {
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 8443 , "https-global" ) ) ) ,
) ,
}
endpoints := [ ] * corev1 . Endpoints {
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service1" ) ,
eUID ( "1" ) ,
subset (
eAddresses ( eAddress ( "10.10.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
) ,
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
watchChan : watchChan ,
}
provider := Provider { }
actual , err := provider . loadIngresses ( client )
require . NoError ( t , err , "error loading ingresses" )
expected := buildConfiguration (
backends (
backend ( "global-default-backend" ,
lbMethod ( "wrr" ) ,
servers (
server ( "https://10.10.0.1:8080" , weight ( 1 ) ) ,
) ,
) ,
) ,
frontends (
frontend ( "global-default-backend" ,
frontendName ( "global-default-frontend" ) ,
passHostHeader ( ) ,
routes (
route ( "/" , "PathPrefix:/" ) ,
) ,
) ,
) ,
)
assert . Equal ( t , expected , actual )
}
2016-05-17 10:50:06 +00:00
func TestRuleType ( t * testing . T ) {
2018-07-06 08:06:04 +00:00
testCases := [ ] struct {
2017-02-06 23:04:30 +00:00
desc string
ingressRuleType string
frontendRuleType string
} {
2016-05-17 10:50:06 +00:00
{
2017-05-18 21:27:10 +00:00
desc : "rule type annotation missing" ,
2017-02-06 23:04:30 +00:00
ingressRuleType : "" ,
frontendRuleType : ruleTypePathPrefix ,
2017-04-11 15:10:46 +00:00
} ,
{
2017-05-19 09:50:36 +00:00
desc : "Path rule type annotation set" ,
2017-05-18 21:27:10 +00:00
ingressRuleType : "Path" ,
frontendRuleType : "Path" ,
2017-04-11 15:10:46 +00:00
} ,
2017-05-19 09:50:36 +00:00
{
desc : "PathStrip rule type annotation set" ,
ingressRuleType : "PathStrip" ,
frontendRuleType : "PathStrip" ,
2016-05-17 10:50:06 +00:00
} ,
{
2018-07-06 08:06:04 +00:00
desc : "PathPrefixStrip rule type annotation set" ,
ingressRuleType : "PathPrefixStrip" ,
frontendRuleType : "PathPrefixStrip" ,
2017-04-11 15:10:46 +00:00
} ,
2017-02-06 23:04:30 +00:00
}
2018-07-06 08:06:04 +00:00
for _ , test := range testCases {
2017-02-06 23:04:30 +00:00
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
2017-12-05 19:24:03 +00:00
ingress := buildIngress ( iRules ( iRule (
iHost ( "host" ) ,
iPaths (
onePath ( iPath ( "/path" ) , iBackend ( "service" , intstr . FromInt ( 80 ) ) ) ,
) ,
) ) )
2017-02-06 23:04:30 +00:00
2018-07-06 08:06:04 +00:00
ingress . Annotations = map [ string ] string {
annotationKubernetesRuleType : test . ingressRuleType ,
2017-02-06 23:04:30 +00:00
}
2017-12-05 19:24:03 +00:00
service := buildService (
sName ( "service" ) ,
sUID ( "1" ) ,
sSpec ( sPorts ( sPort ( 801 , "http" ) ) ) ,
)
2016-05-15 09:16:27 +00:00
2017-04-11 15:10:46 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
2018-02-14 08:56:04 +00:00
ingresses : [ ] * extensionsv1beta1 . Ingress { ingress } ,
services : [ ] * corev1 . Service { service } ,
2017-04-11 15:10:46 +00:00
watchChan : watchChan ,
}
2017-04-17 10:50:02 +00:00
provider := Provider { DisablePassHostHeaders : true }
2017-12-05 19:24:03 +00:00
2017-04-11 15:10:46 +00:00
actualConfig , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2017-02-06 23:04:30 +00:00
2017-12-05 19:24:03 +00:00
expected := buildFrontends ( frontend ( "host/path" ,
routes (
route ( "/path" , fmt . Sprintf ( "%s:/path" , test . frontendRuleType ) ) ,
route ( "host" , "Host:host" ) ) ,
) )
2016-05-15 09:16:27 +00:00
2017-12-05 19:24:03 +00:00
assert . Equal ( t , expected , actualConfig . Frontends )
2017-02-06 23:04:30 +00:00
} )
2016-05-15 09:16:27 +00:00
}
}
2018-07-06 08:06:04 +00:00
func TestRuleFails ( t * testing . T ) {
testCases := [ ] struct {
desc string
ruletypeAnnotation string
requestModifierAnnotation string
} {
{
desc : "Rule-type using unknown rule" ,
ruletypeAnnotation : "Foo: /bar" ,
} ,
{
desc : "Rule type full of spaces" ,
ruletypeAnnotation : " " ,
} ,
{
desc : "Rule type missing both parts of rule" ,
ruletypeAnnotation : " : " ,
} ,
{
desc : "Rule type combined with replacepath modifier" ,
ruletypeAnnotation : "ReplacePath" ,
requestModifierAnnotation : "ReplacePath:/foo" ,
} ,
{
desc : "Rule type combined with replacepathregex modifier" ,
ruletypeAnnotation : "ReplacePath" ,
requestModifierAnnotation : "ReplacePathRegex:/foo /bar" ,
} ,
}
for _ , test := range testCases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
ingress := buildIngress ( iRules ( iRule (
iHost ( "host" ) ,
iPaths (
onePath ( iPath ( "/path" ) , iBackend ( "service" , intstr . FromInt ( 80 ) ) ) ,
) ,
) ) )
ingress . Annotations = map [ string ] string {
annotationKubernetesRuleType : test . ruletypeAnnotation ,
annotationKubernetesRequestModifier : test . requestModifierAnnotation ,
}
_ , err := getRuleForPath ( extensionsv1beta1 . HTTPIngressPath { Path : "/path" } , ingress )
assert . Error ( t , err )
} )
}
}
func TestModifierType ( t * testing . T ) {
testCases := [ ] struct {
desc string
requestModifierAnnotation string
expectedModifierRule string
} {
{
desc : "Request modifier annotation missing" ,
requestModifierAnnotation : "" ,
expectedModifierRule : "" ,
} ,
{
desc : "AddPrefix modifier annotation" ,
requestModifierAnnotation : " AddPrefix: /foo" ,
expectedModifierRule : "AddPrefix:/foo" ,
} ,
{
desc : "ReplacePath modifier annotation" ,
requestModifierAnnotation : " ReplacePath: /foo" ,
expectedModifierRule : "ReplacePath:/foo" ,
} ,
{
desc : "ReplacePathRegex modifier annotation" ,
requestModifierAnnotation : " ReplacePathRegex: /foo /bar" ,
expectedModifierRule : "ReplacePathRegex:/foo /bar" ,
} ,
{
desc : "AddPrefix modifier annotation" ,
requestModifierAnnotation : "AddPrefix:/foo" ,
expectedModifierRule : "AddPrefix:/foo" ,
} ,
{
desc : "ReplacePath modifier annotation" ,
requestModifierAnnotation : "ReplacePath:/foo" ,
expectedModifierRule : "ReplacePath:/foo" ,
} ,
{
desc : "ReplacePathRegex modifier annotation" ,
requestModifierAnnotation : "ReplacePathRegex:/foo /bar" ,
expectedModifierRule : "ReplacePathRegex:/foo /bar" ,
} ,
}
for _ , test := range testCases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
ingress := buildIngress ( iRules ( iRule (
iHost ( "host" ) ,
iPaths (
onePath ( iPath ( "/path" ) , iBackend ( "service" , intstr . FromInt ( 80 ) ) ) ,
) ,
) ) )
ingress . Annotations = map [ string ] string {
annotationKubernetesRequestModifier : test . requestModifierAnnotation ,
}
service := buildService (
sName ( "service" ) ,
sUID ( "1" ) ,
sSpec ( sPorts ( sPort ( 801 , "http" ) ) ) ,
)
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : [ ] * extensionsv1beta1 . Ingress { ingress } ,
services : [ ] * corev1 . Service { service } ,
watchChan : watchChan ,
}
provider := Provider { DisablePassHostHeaders : true }
actualConfig , err := provider . loadIngresses ( client )
require . NoError ( t , err , "error loading ingresses" )
expectedRules := [ ] string { "PathPrefix:/path" }
if len ( test . expectedModifierRule ) > 0 {
expectedRules = append ( expectedRules , test . expectedModifierRule )
}
expected := buildFrontends ( frontend ( "host/path" ,
routes (
route ( "/path" , strings . Join ( expectedRules , ";" ) ) ,
route ( "host" , "Host:host" ) ) ,
) )
assert . Equal ( t , expected , actualConfig . Frontends )
} )
}
}
func TestModifierFails ( t * testing . T ) {
testCases := [ ] struct {
desc string
requestModifierAnnotation string
} {
{
desc : "Request modifier missing part of annotation" ,
requestModifierAnnotation : "AddPrefix: " ,
} ,
{
desc : "Request modifier full of spaces annotation" ,
requestModifierAnnotation : " " ,
} ,
{
desc : "Request modifier missing both parts of annotation" ,
requestModifierAnnotation : " : " ,
} ,
{
desc : "Request modifier using unknown rule" ,
requestModifierAnnotation : "Foo: /bar" ,
} ,
}
for _ , test := range testCases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
ingress := buildIngress ( iRules ( iRule (
iHost ( "host" ) ,
iPaths (
onePath ( iPath ( "/path" ) , iBackend ( "service" , intstr . FromInt ( 80 ) ) ) ,
) ,
) ) )
ingress . Annotations = map [ string ] string {
annotationKubernetesRequestModifier : test . requestModifierAnnotation ,
}
_ , err := getRuleForPath ( extensionsv1beta1 . HTTPIngressPath { Path : "/path" } , ingress )
assert . Error ( t , err )
} )
}
}
2016-05-10 11:43:24 +00:00
func TestGetPassHostHeader ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress (
iNamespace ( "awesome" ) ,
iRules ( iRule (
iHost ( "foo" ) ,
iPaths ( onePath (
iPath ( "/bar" ) ,
iBackend ( "service1" , intstr . FromInt ( 801 ) ) ) ) ,
) ) ,
) ,
}
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sNamespace ( "awesome" ) , sName ( "service1" ) , sUID ( "1" ) ,
sSpec ( sPorts ( sPort ( 801 , "http" ) ) ) ,
) ,
2016-05-10 11:43:24 +00:00
}
2017-12-05 19:24:03 +00:00
2016-05-10 11:43:24 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
watchChan : watchChan ,
}
2017-04-17 10:50:02 +00:00
provider := Provider { DisablePassHostHeaders : true }
2017-12-05 19:24:03 +00:00
2016-05-10 11:43:24 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2016-05-10 11:43:24 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends ( backend ( "foo/bar" , lbMethod ( "wrr" ) , servers ( ) ) ) ,
frontends (
frontend ( "foo/bar" ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
) ,
)
2016-05-10 11:43:24 +00:00
2017-08-18 14:14:03 +00:00
assert . Equal ( t , expected , actual )
2016-05-10 11:43:24 +00:00
}
2017-11-20 01:12:03 +00:00
func TestGetPassTLSCert ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress ( iNamespace ( "awesome" ) ,
iRules ( iRule (
iHost ( "foo" ) ,
iPaths ( onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
}
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "awesome" ) ,
sUID ( "1" ) ,
sSpec ( sPorts ( sPort ( 801 , "http" ) ) ) ,
) ,
2017-11-20 01:12:03 +00:00
}
2017-12-05 19:24:03 +00:00
2017-11-20 01:12:03 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
watchChan : watchChan ,
}
provider := Provider { EnablePassTLSCert : true }
2017-12-05 19:24:03 +00:00
2017-11-20 01:12:03 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2017-11-20 01:12:03 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends ( backend ( "foo/bar" , lbMethod ( "wrr" ) , servers ( ) ) ) ,
frontends ( frontend ( "foo/bar" ,
passHostHeader ( ) ,
passTLSCert ( ) ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ) ,
)
2017-11-20 01:12:03 +00:00
assert . Equal ( t , expected , actual )
}
2016-05-18 15:46:19 +00:00
func TestOnlyReferencesServicesFromOwnNamespace ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress ( iNamespace ( "awesome" ) ,
iRules ( iRule (
iHost ( "foo" ) ,
iPaths ( onePath ( iBackend ( "service" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
2016-05-18 15:46:19 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sNamespace ( "awesome" ) ,
sName ( "service" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
buildService (
sNamespace ( "not-awesome" ) ,
sName ( "service" ) ,
sUID ( "2" ) ,
sSpec (
clusterIP ( "10.0.0.2" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
2016-05-18 15:46:19 +00:00
}
2017-12-05 19:24:03 +00:00
2016-05-18 15:46:19 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
watchChan : watchChan ,
}
2017-04-17 10:50:02 +00:00
provider := Provider { }
2017-12-05 19:24:03 +00:00
2016-05-18 15:46:19 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2016-05-18 15:46:19 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends ( backend ( "foo" , lbMethod ( "wrr" ) , servers ( ) ) ) ,
frontends ( frontend ( "foo" ,
passHostHeader ( ) ,
routes ( route ( "foo" , "Host:foo" ) ) ,
) ) ,
)
2016-05-18 15:46:19 +00:00
2017-08-18 14:14:03 +00:00
assert . Equal ( t , expected , actual )
2016-05-18 15:46:19 +00:00
}
2016-05-25 12:16:19 +00:00
func TestHostlessIngress ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress ( iNamespace ( "awesome" ) ,
iRules ( iRule (
iPaths ( onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 801 ) ) ) ) ) ,
) ,
) ,
}
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "awesome" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 801 , "http" ) ) ) ,
) ,
2016-05-25 12:16:19 +00:00
}
2017-12-05 19:24:03 +00:00
2016-05-25 12:16:19 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
watchChan : watchChan ,
}
2017-04-17 10:50:02 +00:00
provider := Provider { DisablePassHostHeaders : true }
2017-12-05 19:24:03 +00:00
2016-05-25 12:16:19 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2016-05-25 12:16:19 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends ( backend ( "/bar" , lbMethod ( "wrr" ) , servers ( ) ) ) ,
2018-01-02 13:49:11 +00:00
frontends ( frontend ( "/bar" ,
routes ( route ( "/bar" , "PathPrefix:/bar" ) ) ) ) ,
2017-12-05 19:24:03 +00:00
)
2016-05-25 12:16:19 +00:00
2017-08-18 14:14:03 +00:00
assert . Equal ( t , expected , actual )
2016-04-28 00:23:55 +00:00
}
2017-02-03 16:47:48 +00:00
func TestServiceAnnotations ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress ( iNamespace ( "testing" ) ,
iRules (
iRule (
iHost ( "foo" ) ,
iPaths ( onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
iRule (
iHost ( "bar" ) ,
iPaths ( onePath ( iBackend ( "service2" , intstr . FromInt ( 802 ) ) ) ) ) ,
2018-01-31 14:32:04 +00:00
iRule (
iHost ( "baz" ) ,
iPaths ( onePath ( iBackend ( "service3" , intstr . FromInt ( 803 ) ) ) ) ) ,
2017-12-21 21:44:06 +00:00
iRule (
iHost ( "max-conn" ) ,
iPaths ( onePath ( iBackend ( "service4" , intstr . FromInt ( 804 ) ) ) ) ) ,
2017-12-05 19:24:03 +00:00
) ,
) ,
}
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
2018-01-26 12:29:42 +00:00
sAnnotation ( annotationKubernetesCircuitBreakerExpression , "NetworkErrorRatio() > 0.5" ) ,
sAnnotation ( annotationKubernetesLoadBalancerMethod , "drr" ) ,
2017-12-05 19:24:03 +00:00
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
buildService (
sName ( "service2" ) ,
sNamespace ( "testing" ) ,
sUID ( "2" ) ,
2018-01-26 12:29:42 +00:00
sAnnotation ( annotationKubernetesCircuitBreakerExpression , "" ) ,
2017-12-05 19:24:03 +00:00
sAnnotation ( label . TraefikBackendLoadBalancerSticky , "true" ) ,
sSpec (
clusterIP ( "10.0.0.2" ) ,
sPorts ( sPort ( 802 , "" ) ) ) ,
) ,
2018-01-31 14:32:04 +00:00
buildService (
sName ( "service3" ) ,
sNamespace ( "testing" ) ,
sUID ( "3" ) ,
2018-01-26 12:29:42 +00:00
sAnnotation ( annotationKubernetesBuffering , `
maxrequestbodybytes : 10485760
memrequestbodybytes : 2097153
maxresponsebodybytes : 10485761
memresponsebodybytes : 2097152
retryexpression : IsNetworkError ( ) && Attempts ( ) <= 2
` ) ,
2018-01-31 14:32:04 +00:00
sSpec (
clusterIP ( "10.0.0.3" ) ,
2018-04-16 12:44:04 +00:00
sPorts ( sPort ( 803 , "http" ) ) ) ,
2018-01-31 14:32:04 +00:00
) ,
2017-12-21 21:44:06 +00:00
buildService (
sName ( "service4" ) ,
sNamespace ( "testing" ) ,
sUID ( "4" ) ,
2018-01-26 12:29:42 +00:00
sAnnotation ( annotationKubernetesMaxConnExtractorFunc , "client.ip" ) ,
sAnnotation ( annotationKubernetesMaxConnAmount , "6" ) ,
2017-12-21 21:44:06 +00:00
sSpec (
clusterIP ( "10.0.0.4" ) ,
2018-04-16 12:44:04 +00:00
sPorts ( sPort ( 804 , "http" ) ) ) ,
2017-12-21 21:44:06 +00:00
) ,
2017-01-25 13:11:00 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
endpoints := [ ] * corev1 . Endpoints {
2017-12-05 19:24:03 +00:00
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service1" ) ,
eUID ( "1" ) ,
subset (
eAddresses ( eAddress ( "10.10.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
subset (
eAddresses ( eAddress ( "10.21.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
) ,
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service2" ) ,
eUID ( "2" ) ,
subset (
eAddresses ( eAddress ( "10.15.0.1" ) ) ,
2018-04-16 12:44:04 +00:00
ePorts ( ePort ( 8080 , "" ) ) ) ,
2017-12-05 19:24:03 +00:00
subset (
eAddresses ( eAddress ( "10.15.0.2" ) ) ,
2018-04-16 12:44:04 +00:00
ePorts ( ePort ( 8080 , "" ) ) ) ,
2017-12-05 19:24:03 +00:00
) ,
2018-01-31 14:32:04 +00:00
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service3" ) ,
eUID ( "3" ) ,
subset (
eAddresses ( eAddress ( "10.14.0.1" ) ) ,
ePorts ( ePort ( 8080 , "http" ) ) ) ,
subset (
eAddresses ( eAddress ( "10.12.0.1" ) ) ,
ePorts ( ePort ( 8080 , "http" ) ) ) ,
) ,
2017-12-21 21:44:06 +00:00
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service4" ) ,
eUID ( "4" ) ,
subset (
eAddresses ( eAddress ( "10.4.0.1" ) ) ,
ePorts ( ePort ( 8080 , "http" ) ) ) ,
subset (
eAddresses ( eAddress ( "10.4.0.2" ) ) ,
ePorts ( ePort ( 8080 , "http" ) ) ) ,
) ,
2017-01-25 13:11:00 +00:00
}
2017-12-05 19:24:03 +00:00
2017-01-25 13:11:00 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
watchChan : watchChan ,
}
2017-04-17 10:50:02 +00:00
provider := Provider { }
2017-12-05 19:24:03 +00:00
2017-01-25 13:11:00 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2017-01-25 13:11:00 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends (
backend ( "foo/bar" ,
servers (
server ( "http://10.10.0.1:8080" , weight ( 1 ) ) ,
server ( "http://10.21.0.1:8080" , weight ( 1 ) ) ) ,
lbMethod ( "drr" ) ,
circuitBreaker ( "NetworkErrorRatio() > 0.5" ) ,
) ,
backend ( "bar" ,
servers (
server ( "http://10.15.0.1:8080" , weight ( 1 ) ) ,
server ( "http://10.15.0.2:8080" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) , lbSticky ( ) ,
) ,
2018-01-31 14:32:04 +00:00
backend ( "baz" ,
servers (
server ( "http://10.14.0.1:8080" , weight ( 1 ) ) ,
server ( "http://10.12.0.1:8080" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
buffering (
maxRequestBodyBytes ( 10485760 ) ,
2018-01-26 12:29:42 +00:00
memRequestBodyBytes ( 2097153 ) ,
maxResponseBodyBytes ( 10485761 ) ,
2018-01-31 14:32:04 +00:00
memResponseBodyBytes ( 2097152 ) ,
retrying ( "IsNetworkError() && Attempts() <= 2" ) ,
) ,
) ,
2017-12-21 21:44:06 +00:00
backend ( "max-conn" ,
servers (
server ( "http://10.4.0.1:8080" , weight ( 1 ) ) ,
server ( "http://10.4.0.2:8080" , weight ( 1 ) ) ) ,
maxConnExtractorFunc ( "client.ip" ) ,
maxConnAmount ( 6 ) ,
lbMethod ( "wrr" ) ,
) ,
2017-12-05 19:24:03 +00:00
) ,
frontends (
frontend ( "foo/bar" ,
passHostHeader ( ) ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
frontend ( "bar" ,
passHostHeader ( ) ,
2017-12-21 21:44:06 +00:00
routes ( route ( "bar" , "Host:bar" ) ) ) ,
2018-01-31 14:32:04 +00:00
frontend ( "baz" ,
passHostHeader ( ) ,
2017-12-21 21:44:06 +00:00
routes ( route ( "baz" , "Host:baz" ) ) ) ,
frontend ( "max-conn" ,
passHostHeader ( ) ,
routes (
route ( "max-conn" , "Host:max-conn" ) ) ) ,
2017-12-05 19:24:03 +00:00
) ,
)
2017-01-25 13:11:00 +00:00
2017-10-16 15:38:03 +00:00
assert . EqualValues ( t , expected , actual )
2017-01-25 13:11:00 +00:00
}
2017-02-10 11:27:30 +00:00
func TestIngressAnnotations ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesPreserveHost , "false" ) ,
2017-12-05 19:24:03 +00:00
iRules (
iRule (
iHost ( "foo" ) ,
iPaths ( onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesPreserveHost , "true" ) ,
2018-02-01 18:04:04 +00:00
iAnnotation ( annotationKubernetesIngressClass , traefikDefaultRealm ) ,
2017-12-05 19:24:03 +00:00
iRules (
iRule (
iHost ( "other" ) ,
iPaths ( onePath ( iPath ( "/stuff" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesPassTLSCert , "true" ) ,
2018-02-01 18:04:04 +00:00
iAnnotation ( annotationKubernetesIngressClass , traefikDefaultRealm ) ,
2017-12-05 19:24:03 +00:00
iRules (
iRule (
iHost ( "other" ) ,
iPaths ( onePath ( iPath ( "/sslstuff" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesFrontendEntryPoints , "http,https" ) ,
2018-02-01 18:04:04 +00:00
iAnnotation ( annotationKubernetesIngressClass , traefikDefaultRealm ) ,
2017-12-05 19:24:03 +00:00
iRules (
iRule (
iHost ( "other" ) ,
iPaths ( onePath ( iPath ( "/" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesAuthType , "basic" ) ,
iAnnotation ( annotationKubernetesAuthSecret , "mySecret" ) ,
iRules (
iRule (
iHost ( "basic" ) ,
iPaths ( onePath ( iPath ( "/auth" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
2018-02-01 18:04:04 +00:00
iAnnotation ( annotationKubernetesIngressClass , traefikDefaultRealm + "-other" ) ,
2017-12-05 19:24:03 +00:00
iRules (
iRule (
iHost ( "herp" ) ,
iPaths ( onePath ( iPath ( "/derp" ) , iBackend ( "service2" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
2018-03-23 16:40:04 +00:00
iAnnotation ( annotationKubernetesWhiteListSourceRange , "1.1.1.1/24, 1234:abcd::42/32" ) ,
iAnnotation ( annotationKubernetesWhiteListUseXForwardedFor , "true" ) ,
2017-12-05 19:24:03 +00:00
iRules (
iRule (
iHost ( "test" ) ,
iPaths ( onePath ( iPath ( "/whitelist-source-range" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesRewriteTarget , "/" ) ,
iRules (
iRule (
iHost ( "rewrite" ) ,
iPaths ( onePath ( iPath ( "/api" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesAuthRealm , "customized" ) ,
iRules (
iRule (
iHost ( "auth-realm-customized" ) ,
iPaths ( onePath ( iPath ( "/auth-realm-customized" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesRedirectEntryPoint , "https" ) ,
2017-12-05 19:24:03 +00:00
iRules (
iRule (
iHost ( "redirect" ) ,
iPaths ( onePath ( iPath ( "/https" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
2017-12-21 16:47:50 +00:00
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesIngressClass , "traefik" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesErrorPages , `
foo :
status :
- "123"
- "456"
backend : bar
query : / bar
` ) ,
2017-12-21 16:47:50 +00:00
iRules (
iRule (
iHost ( "error-pages" ) ,
iPaths ( onePath ( iPath ( "/errorpages" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
2017-12-21 21:07:37 +00:00
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesIngressClass , "traefik" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesRateLimit , `
extractorfunc : client . ip
rateset :
bar :
period : 3 s
average : 6
burst : 9
foo :
period : 6 s
average : 12
burst : 18
` ) ,
2017-12-21 21:07:37 +00:00
iRules (
iRule (
iHost ( "rate-limit" ) ,
iPaths ( onePath ( iPath ( "/ratelimit" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
2018-02-19 14:36:03 +00:00
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesAppRoot , "/root" ) ,
iRules (
iRule (
iHost ( "root" ) ,
iPaths (
onePath ( iPath ( "/" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ,
onePath ( iPath ( "/root1" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ,
) ,
) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesAppRoot , "/root2" ) ,
iAnnotation ( annotationKubernetesRewriteTarget , "/abc" ) ,
iRules (
iRule (
iHost ( "root2" ) ,
iPaths (
onePath ( iPath ( "/" ) , iBackend ( "service2" , intstr . FromInt ( 80 ) ) ) ,
) ,
) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesRuleType , ruleTypeReplacePath ) ,
iAnnotation ( annotationKubernetesRewriteTarget , "/abc" ) ,
iRules (
iRule (
iHost ( "root2" ) ,
iPaths (
onePath ( iPath ( "/" ) , iBackend ( "service2" , intstr . FromInt ( 80 ) ) ) ,
) ,
) ,
) ,
) ,
2018-01-02 17:03:50 +00:00
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesIngressClass , "traefik" ) ,
iAnnotation ( annotationKubernetesCustomRequestHeaders , "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8" ) ,
iAnnotation ( annotationKubernetesCustomResponseHeaders , "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8" ) ,
iAnnotation ( annotationKubernetesSSLProxyHeaders , "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8" ) ,
iAnnotation ( annotationKubernetesAllowedHosts , "foo, fii, fuu" ) ,
iAnnotation ( annotationKubernetesProxyHeaders , "foo, fii, fuu" ) ,
iAnnotation ( annotationKubernetesHSTSMaxAge , "666" ) ,
2018-05-14 09:44:03 +00:00
iAnnotation ( annotationKubernetesSSLForceHost , "true" ) ,
2018-01-02 17:03:50 +00:00
iAnnotation ( annotationKubernetesSSLRedirect , "true" ) ,
iAnnotation ( annotationKubernetesSSLTemporaryRedirect , "true" ) ,
iAnnotation ( annotationKubernetesHSTSIncludeSubdomains , "true" ) ,
iAnnotation ( annotationKubernetesForceHSTSHeader , "true" ) ,
iAnnotation ( annotationKubernetesHSTSPreload , "true" ) ,
iAnnotation ( annotationKubernetesFrameDeny , "true" ) ,
iAnnotation ( annotationKubernetesContentTypeNosniff , "true" ) ,
iAnnotation ( annotationKubernetesBrowserXSSFilter , "true" ) ,
2018-03-02 13:24:03 +00:00
iAnnotation ( annotationKubernetesCustomBrowserXSSValue , "foo" ) ,
2018-01-02 17:03:50 +00:00
iAnnotation ( annotationKubernetesIsDevelopment , "true" ) ,
iAnnotation ( annotationKubernetesSSLHost , "foo" ) ,
iAnnotation ( annotationKubernetesCustomFrameOptionsValue , "foo" ) ,
iAnnotation ( annotationKubernetesContentSecurityPolicy , "foo" ) ,
iAnnotation ( annotationKubernetesPublicKey , "foo" ) ,
iAnnotation ( annotationKubernetesReferrerPolicy , "foo" ) ,
iRules (
iRule (
iHost ( "custom-headers" ) ,
iPaths ( onePath ( iPath ( "/customheaders" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
2017-02-10 11:27:30 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sType ( "ExternalName" ) ,
sExternalName ( "example.com" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
buildService (
sName ( "service2" ) ,
sNamespace ( "testing" ) ,
sUID ( "2" ) ,
sSpec (
clusterIP ( "10.0.0.2" ) ,
sPorts ( sPort ( 802 , "" ) ) ) ,
) ,
2017-02-10 11:27:30 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
secrets := [ ] * corev1 . Secret {
2018-02-01 18:04:04 +00:00
{
2018-02-14 08:56:04 +00:00
ObjectMeta : metav1 . ObjectMeta {
2018-02-01 18:04:04 +00:00
Name : "mySecret" ,
UID : "1" ,
Namespace : "testing" ,
} ,
Data : map [ string ] [ ] byte { "auth" : [ ] byte ( "myUser:myEncodedPW" ) } ,
2017-04-23 14:17:20 +00:00
} ,
2018-02-01 18:04:04 +00:00
}
2017-02-10 11:27:30 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
2017-04-23 14:17:20 +00:00
secrets : secrets ,
2017-02-10 11:27:30 +00:00
watchChan : watchChan ,
}
2017-04-17 10:50:02 +00:00
provider := Provider { }
2017-12-05 19:24:03 +00:00
2017-02-10 11:27:30 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2017-02-10 11:27:30 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends (
backend ( "foo/bar" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "other/stuff" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "other/" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "other/sslstuff" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "basic/auth" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "redirect/https" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "test/whitelist-source-range" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "rewrite/api" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
2017-12-21 16:47:50 +00:00
backend ( "error-pages/errorpages" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
2017-12-21 21:07:37 +00:00
backend ( "rate-limit/ratelimit" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
2018-01-02 17:03:50 +00:00
backend ( "custom-headers/customheaders" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
2018-02-19 14:36:03 +00:00
backend ( "root/" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "root/root1" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "root2/" ,
servers ( ) ,
lbMethod ( "wrr" ) ,
) ,
2017-12-05 19:24:03 +00:00
) ,
frontends (
frontend ( "foo/bar" ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
frontend ( "other/stuff" ,
passHostHeader ( ) ,
routes (
route ( "/stuff" , "PathPrefix:/stuff" ) ,
route ( "other" , "Host:other" ) ) ,
) ,
frontend ( "other/" ,
passHostHeader ( ) ,
entryPoints ( "http" , "https" ) ,
routes (
route ( "/" , "PathPrefix:/" ) ,
route ( "other" , "Host:other" ) ) ,
) ,
frontend ( "other/sslstuff" ,
passHostHeader ( ) ,
passTLSCert ( ) ,
routes (
route ( "/sslstuff" , "PathPrefix:/sslstuff" ) ,
route ( "other" , "Host:other" ) ) ,
) ,
frontend ( "other/sslstuff" ,
passHostHeader ( ) ,
passTLSCert ( ) ,
routes (
route ( "/sslstuff" , "PathPrefix:/sslstuff" ) ,
route ( "other" , "Host:other" ) ) ,
) ,
frontend ( "basic/auth" ,
passHostHeader ( ) ,
2018-07-02 09:52:04 +00:00
basicAuthDeprecated ( "myUser:myEncodedPW" ) ,
2017-12-05 19:24:03 +00:00
routes (
route ( "/auth" , "PathPrefix:/auth" ) ,
route ( "basic" , "Host:basic" ) ) ,
) ,
frontend ( "redirect/https" ,
passHostHeader ( ) ,
2017-12-15 21:16:48 +00:00
redirectEntryPoint ( "https" ) ,
2017-12-05 19:24:03 +00:00
routes (
route ( "/https" , "PathPrefix:/https" ) ,
route ( "redirect" , "Host:redirect" ) ) ,
) ,
frontend ( "test/whitelist-source-range" ,
passHostHeader ( ) ,
2018-03-23 16:40:04 +00:00
whiteList ( true , "1.1.1.1/24" , "1234:abcd::42/32" ) ,
2017-12-05 19:24:03 +00:00
routes (
route ( "/whitelist-source-range" , "PathPrefix:/whitelist-source-range" ) ,
route ( "test" , "Host:test" ) ) ,
) ,
frontend ( "rewrite/api" ,
passHostHeader ( ) ,
routes (
2018-07-09 22:26:03 +00:00
route ( "/api" , "PathPrefix:/api;ReplacePathRegex: ^/api/(.*) /$1" ) ,
2017-12-05 19:24:03 +00:00
route ( "rewrite" , "Host:rewrite" ) ) ,
) ,
2017-12-21 16:47:50 +00:00
frontend ( "error-pages/errorpages" ,
passHostHeader ( ) ,
errorPage ( "foo" , errorQuery ( "/bar" ) , errorStatus ( "123" , "456" ) , errorBackend ( "bar" ) ) ,
routes (
route ( "/errorpages" , "PathPrefix:/errorpages" ) ,
route ( "error-pages" , "Host:error-pages" ) ) ,
) ,
2017-12-21 21:07:37 +00:00
frontend ( "rate-limit/ratelimit" ,
passHostHeader ( ) ,
rateLimit ( rateExtractorFunc ( "client.ip" ) ,
rateSet ( "foo" , limitPeriod ( 6 * time . Second ) , limitAverage ( 12 ) , limitBurst ( 18 ) ) ,
rateSet ( "bar" , limitPeriod ( 3 * time . Second ) , limitAverage ( 6 ) , limitBurst ( 9 ) ) ) ,
routes (
route ( "/ratelimit" , "PathPrefix:/ratelimit" ) ,
route ( "rate-limit" , "Host:rate-limit" ) ) ,
) ,
2018-01-02 17:03:50 +00:00
frontend ( "custom-headers/customheaders" ,
passHostHeader ( ) ,
headers ( & types . Headers {
CustomRequestHeaders : map [ string ] string {
"Access-Control-Allow-Methods" : "POST,GET,OPTIONS" ,
"Content-Type" : "application/json; charset=utf-8" ,
} ,
CustomResponseHeaders : map [ string ] string {
"Access-Control-Allow-Methods" : "POST,GET,OPTIONS" ,
"Content-Type" : "application/json; charset=utf-8" ,
} ,
SSLProxyHeaders : map [ string ] string {
"Access-Control-Allow-Methods" : "POST,GET,OPTIONS" ,
"Content-Type" : "application/json; charset=utf-8" ,
} ,
AllowedHosts : [ ] string { "foo" , "fii" , "fuu" } ,
HostsProxyHeaders : [ ] string { "foo" , "fii" , "fuu" } ,
STSSeconds : 666 ,
2018-05-14 09:44:03 +00:00
SSLForceHost : true ,
2018-01-02 17:03:50 +00:00
SSLRedirect : true ,
SSLTemporaryRedirect : true ,
STSIncludeSubdomains : true ,
STSPreload : true ,
ForceSTSHeader : true ,
FrameDeny : true ,
ContentTypeNosniff : true ,
BrowserXSSFilter : true ,
IsDevelopment : true ,
CustomFrameOptionsValue : "foo" ,
SSLHost : "foo" ,
ContentSecurityPolicy : "foo" ,
PublicKey : "foo" ,
ReferrerPolicy : "foo" ,
2018-03-02 13:24:03 +00:00
CustomBrowserXSSValue : "foo" ,
2018-01-02 17:03:50 +00:00
} ) ,
routes (
route ( "/customheaders" , "PathPrefix:/customheaders" ) ,
route ( "custom-headers" , "Host:custom-headers" ) ) ,
) ,
2018-02-19 14:36:03 +00:00
frontend ( "root/" ,
passHostHeader ( ) ,
routes (
route ( "/" , "PathPrefix:/;ReplacePath:/root" ) ,
route ( "root" , "Host:root" ) ,
) ,
) ,
frontend ( "root/root1" ,
passHostHeader ( ) ,
routes (
route ( "/root1" , "PathPrefix:/root1" ) ,
route ( "root" , "Host:root" ) ,
) ,
) ,
2017-12-05 19:24:03 +00:00
) ,
)
2017-02-10 11:27:30 +00:00
2017-07-07 19:27:54 +00:00
assert . Equal ( t , expected , actual )
2017-02-10 11:27:30 +00:00
}
2018-02-01 18:04:04 +00:00
func TestIngressClassAnnotation ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2018-02-01 18:04:04 +00:00
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesIngressClass , traefikDefaultIngressClass ) ,
iRules (
iRule (
iHost ( "other" ) ,
iPaths ( onePath ( iPath ( "/stuff" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesIngressClass , "" ) ,
iRules (
iRule (
iHost ( "other" ) ,
iPaths ( onePath ( iPath ( "/sslstuff" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
iRules (
iRule (
iHost ( "other" ) ,
iPaths ( onePath ( iPath ( "/" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesIngressClass , traefikDefaultIngressClass + "-other" ) ,
iRules (
iRule (
2018-06-22 14:54:03 +00:00
iHost ( "foo" ) ,
iPaths ( onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesIngressClass , "custom" ) ,
iRules (
iRule (
iHost ( "foo" ) ,
iPaths ( onePath ( iPath ( "/bar" ) , iBackend ( "service2" , intstr . FromInt ( 80 ) ) ) ) ) ,
2018-02-01 18:04:04 +00:00
) ,
) ,
}
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2018-02-01 18:04:04 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sType ( "ExternalName" ) ,
sExternalName ( "example.com" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
2018-06-22 14:54:03 +00:00
buildService (
sName ( "service2" ) ,
sNamespace ( "testing" ) ,
sUID ( "2" ) ,
sSpec (
clusterIP ( "10.0.0.2" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
}
endpoints := [ ] * corev1 . Endpoints {
buildEndpoint (
eName ( "service2" ) ,
eUID ( "1" ) ,
eNamespace ( "testing" ) ,
subset (
eAddresses ( eAddress ( "10.10.0.1" ) ) ,
ePorts ( ePort ( 80 , "http" ) ) ) ,
) ,
2018-02-01 18:04:04 +00:00
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
2018-06-22 14:54:03 +00:00
endpoints : endpoints ,
2018-02-01 18:04:04 +00:00
watchChan : watchChan ,
}
testCases := [ ] struct {
desc string
provider Provider
expected * types . Configuration
} {
{
desc : "Empty IngressClass annotation" ,
provider : Provider { } ,
expected : buildConfiguration (
backends (
backend ( "other/stuff" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "other/" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "other/sslstuff" ,
servers (
server ( "http://example.com" , weight ( 1 ) ) ,
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
) ,
frontends (
frontend ( "other/stuff" ,
passHostHeader ( ) ,
routes (
route ( "/stuff" , "PathPrefix:/stuff" ) ,
route ( "other" , "Host:other" ) ) ,
) ,
frontend ( "other/" ,
passHostHeader ( ) ,
routes (
route ( "/" , "PathPrefix:/" ) ,
route ( "other" , "Host:other" ) ) ,
) ,
frontend ( "other/sslstuff" ,
passHostHeader ( ) ,
routes (
route ( "/sslstuff" , "PathPrefix:/sslstuff" ) ,
route ( "other" , "Host:other" ) ) ,
) ,
) ,
) ,
} ,
{
desc : "Provided IngressClass annotation" ,
provider : Provider { IngressClass : traefikDefaultRealm + "-other" } ,
expected : buildConfiguration (
backends (
2018-06-22 14:54:03 +00:00
backend ( "foo/bar" ,
2018-02-01 18:04:04 +00:00
servers (
server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
) ,
frontends (
2018-06-22 14:54:03 +00:00
frontend ( "foo/bar" ,
passHostHeader ( ) ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
) ,
) ,
} ,
{
desc : "Provided IngressClass annotation" ,
provider : Provider { IngressClass : "custom" } ,
expected : buildConfiguration (
backends (
backend ( "foo/bar" ,
servers (
server ( "http://10.10.0.1:80" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
) ,
frontends (
frontend ( "foo/bar" ,
2018-02-01 18:04:04 +00:00
passHostHeader ( ) ,
routes (
2018-06-22 14:54:03 +00:00
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
2018-02-01 18:04:04 +00:00
) ,
) ,
) ,
} ,
}
for _ , test := range testCases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
actual , err := test . provider . loadIngresses ( client )
require . NoError ( t , err , "error loading ingresses" )
assert . Equal ( t , test . expected , actual )
} )
}
}
2017-07-29 16:35:23 +00:00
func TestPriorityHeaderValue ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesPriority , "1337" ) ,
2017-12-05 19:24:03 +00:00
iRules (
iRule (
iHost ( "foo" ) ,
iPaths ( onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
2017-07-29 16:35:23 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sType ( "ExternalName" ) ,
sExternalName ( "example.com" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
2017-07-29 16:35:23 +00:00
}
2018-02-14 08:56:04 +00:00
var endpoints [ ] * corev1 . Endpoints
2017-07-29 16:35:23 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
watchChan : watchChan ,
}
provider := Provider { }
2017-12-05 19:24:03 +00:00
2017-07-29 16:35:23 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2017-07-29 16:35:23 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends (
backend ( "foo/bar" ,
servers ( server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
) ,
frontends (
frontend ( "foo/bar" ,
passHostHeader ( ) ,
priority ( 1337 ) ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
) ,
)
2017-07-29 16:35:23 +00:00
assert . Equal ( t , expected , actual )
}
2017-11-20 01:12:03 +00:00
func TestInvalidPassTLSCertValue ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesPassTLSCert , "herpderp" ) ,
2017-12-05 19:24:03 +00:00
iRules (
iRule (
iHost ( "foo" ) ,
iPaths ( onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
2017-11-20 01:12:03 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sType ( "ExternalName" ) ,
sExternalName ( "example.com" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
2017-11-20 01:12:03 +00:00
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
watchChan : watchChan ,
}
provider := Provider { }
2017-12-05 19:24:03 +00:00
2017-11-20 01:12:03 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2017-11-20 01:12:03 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends (
backend ( "foo/bar" ,
servers ( server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
) ,
frontends (
frontend ( "foo/bar" ,
passHostHeader ( ) ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
) ,
)
2017-11-20 01:12:03 +00:00
assert . Equal ( t , expected , actual )
}
2017-02-14 19:54:27 +00:00
func TestInvalidPassHostHeaderValue ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesPreserveHost , "herpderp" ) ,
2017-12-05 19:24:03 +00:00
iRules (
iRule (
iHost ( "foo" ) ,
iPaths ( onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
2017-02-14 19:54:27 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sType ( "ExternalName" ) ,
sExternalName ( "example.com" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
2017-02-14 19:54:27 +00:00
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
watchChan : watchChan ,
}
2017-04-17 10:50:02 +00:00
provider := Provider { }
2017-12-05 19:24:03 +00:00
2017-02-14 19:54:27 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2017-02-14 19:54:27 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends (
backend ( "foo/bar" ,
servers ( server ( "http://example.com" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
) ,
frontends (
frontend ( "foo/bar" ,
passHostHeader ( ) ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
) ,
)
2017-02-14 19:54:27 +00:00
2017-08-18 14:14:03 +00:00
assert . Equal ( t , expected , actual )
2017-02-14 19:54:27 +00:00
}
2017-03-17 15:34:34 +00:00
func TestKubeAPIErrors ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress (
iNamespace ( "testing" ) ,
iRules (
iRule (
iHost ( "foo" ) ,
iPaths ( onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
}
2017-03-17 15:34:34 +00:00
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
}
2017-03-17 15:34:34 +00:00
watchChan := make ( chan interface { } )
apiErr := errors . New ( "failed kube api call" )
testCases := [ ] struct {
desc string
apiServiceErr error
apiEndpointsErr error
} {
{
desc : "failed service call" ,
apiServiceErr : apiErr ,
} ,
{
desc : "failed endpoints call" ,
apiEndpointsErr : apiErr ,
} ,
}
for _ , tc := range testCases {
tc := tc
t . Run ( tc . desc , func ( t * testing . T ) {
t . Parallel ( )
client := clientMock {
ingresses : ingresses ,
services : services ,
watchChan : watchChan ,
apiServiceError : tc . apiServiceErr ,
apiEndpointsError : tc . apiEndpointsErr ,
}
2017-04-17 10:50:02 +00:00
provider := Provider { }
2017-12-05 19:24:03 +00:00
2018-07-03 16:58:03 +00:00
if _ , err := provider . loadIngresses ( client ) ; err != nil {
if client . apiServiceError != nil {
assert . EqualError ( t , err , "failed kube api call" )
}
if client . apiEndpointsError != nil {
assert . EqualError ( t , err , "failed kube api call" )
}
2017-03-17 15:34:34 +00:00
}
} )
}
}
func TestMissingResources ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress (
iNamespace ( "testing" ) ,
iRules (
iRule (
iHost ( "fully_working" ) ,
iPaths ( onePath ( iBackend ( "fully_working_service" , intstr . FromInt ( 80 ) ) ) ) ) ,
iRule (
iHost ( "missing_service" ) ,
iPaths ( onePath ( iBackend ( "missing_service_service" , intstr . FromInt ( 80 ) ) ) ) ) ,
iRule (
iHost ( "missing_endpoints" ) ,
iPaths ( onePath ( iBackend ( "missing_endpoints_service" , intstr . FromInt ( 80 ) ) ) ) ) ,
iRule (
iHost ( "missing_endpoint_subsets" ) ,
iPaths ( onePath ( iBackend ( "missing_endpoint_subsets_service" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
}
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "fully_working_service" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
buildService (
sName ( "missing_endpoints_service" ) ,
sNamespace ( "testing" ) ,
sUID ( "3" ) ,
sSpec (
clusterIP ( "10.0.0.3" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
buildService (
sName ( "missing_endpoint_subsets_service" ) ,
sNamespace ( "testing" ) ,
sUID ( "4" ) ,
sSpec (
clusterIP ( "10.0.0.4" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
2017-03-17 15:34:34 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
endpoints := [ ] * corev1 . Endpoints {
2017-12-05 19:24:03 +00:00
buildEndpoint (
eName ( "fully_working_service" ) ,
eUID ( "1" ) ,
eNamespace ( "testing" ) ,
subset (
eAddresses ( eAddress ( "10.10.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
) ,
buildEndpoint (
eName ( "missing_endpoint_subsets_service" ) ,
eUID ( "4" ) ,
eNamespace ( "testing" ) ,
) ,
2017-03-17 15:34:34 +00:00
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
watchChan : watchChan ,
}
2017-04-13 22:00:25 +00:00
2017-04-17 10:50:02 +00:00
provider := Provider { }
2017-12-05 19:24:03 +00:00
2017-03-17 15:34:34 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2017-03-17 15:34:34 +00:00
2017-12-05 19:24:03 +00:00
expected := buildConfiguration (
backends (
backend ( "fully_working" ,
servers ( server ( "http://10.10.0.1:8080" , weight ( 1 ) ) ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "missing_service" ,
servers ( ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "missing_endpoints" ,
servers ( ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "missing_endpoint_subsets" ,
servers ( ) ,
lbMethod ( "wrr" ) ,
) ,
) ,
frontends (
frontend ( "fully_working" ,
passHostHeader ( ) ,
routes ( route ( "fully_working" , "Host:fully_working" ) ) ,
) ,
frontend ( "missing_endpoints" ,
passHostHeader ( ) ,
routes ( route ( "missing_endpoints" , "Host:missing_endpoints" ) ) ,
) ,
frontend ( "missing_endpoint_subsets" ,
passHostHeader ( ) ,
routes ( route ( "missing_endpoint_subsets" , "Host:missing_endpoint_subsets" ) ) ,
) ,
) ,
)
2017-03-17 15:34:34 +00:00
2017-08-18 14:14:03 +00:00
assert . Equal ( t , expected , actual )
2017-03-17 15:34:34 +00:00
}
2018-07-02 09:52:04 +00:00
func TestLoadIngressesBasicAuth ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2017-12-05 19:24:03 +00:00
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesAuthType , "basic" ) ,
iAnnotation ( annotationKubernetesAuthSecret , "mySecret" ) ,
iRules (
iRule (
iHost ( "basic" ) ,
iPaths ( onePath ( iPath ( "/auth" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
2017-04-23 14:17:20 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2017-12-05 19:24:03 +00:00
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sType ( "ExternalName" ) ,
sExternalName ( "example.com" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
2017-04-23 14:17:20 +00:00
}
2017-12-05 19:24:03 +00:00
2018-02-14 08:56:04 +00:00
secrets := [ ] * corev1 . Secret { {
ObjectMeta : metav1 . ObjectMeta {
2017-12-05 19:24:03 +00:00
Name : "mySecret" ,
UID : "1" ,
Namespace : "testing" ,
2017-04-23 14:17:20 +00:00
} ,
2017-12-05 19:24:03 +00:00
Data : map [ string ] [ ] byte {
"auth" : [ ] byte ( "myUser:myEncodedPW" ) ,
} ,
} }
2017-04-23 14:17:20 +00:00
2018-02-14 08:56:04 +00:00
var endpoints [ ] * corev1 . Endpoints
2017-04-23 14:17:20 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
secrets : secrets ,
endpoints : endpoints ,
watchChan : watchChan ,
}
provider := Provider { }
2017-12-05 19:24:03 +00:00
2017-04-23 14:17:20 +00:00
actual , err := provider . loadIngresses ( client )
2017-12-05 19:24:03 +00:00
require . NoError ( t , err , "error loading ingresses" )
2017-04-23 14:17:20 +00:00
actual = provider . loadConfig ( * actual )
2017-12-15 10:48:03 +00:00
require . NotNil ( t , actual )
2018-07-02 09:52:04 +00:00
got := actual . Frontends [ "basic/auth" ] . Auth . Basic . Users
assert . Equal ( t , types . Users { "myUser:myEncodedPW" } , got )
}
func TestLoadIngressesForwardAuth ( t * testing . T ) {
ingresses := [ ] * extensionsv1beta1 . Ingress {
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesAuthType , "forward" ) ,
iAnnotation ( annotationKubernetesAuthForwardURL , "https://auth.host" ) ,
iAnnotation ( annotationKubernetesAuthForwardTrustHeaders , "true" ) ,
iAnnotation ( annotationKubernetesAuthForwardResponseHeaders , "X-Auth,X-Test,X-Secret" ) ,
iRules (
iRule ( iHost ( "foo" ) ,
iPaths (
onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
}
services := [ ] * corev1 . Service {
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
}
endpoints := [ ] * corev1 . Endpoints {
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service1" ) ,
eUID ( "1" ) ,
subset (
eAddresses ( eAddress ( "10.10.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
) ,
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
watchChan : watchChan ,
}
provider := Provider { }
actual , err := provider . loadIngresses ( client )
require . NoError ( t , err , "error loading ingresses" )
expected := buildConfiguration (
backends (
backend ( "foo/bar" ,
lbMethod ( "wrr" ) ,
servers (
server ( "http://10.10.0.1:8080" , weight ( 1 ) ) ) ,
) ,
) ,
frontends (
frontend ( "foo/bar" ,
passHostHeader ( ) ,
auth ( forwardAuth ( "https://auth.host" ,
fwdTrustForwardHeader ( ) ,
fwdAuthResponseHeaders ( "X-Auth" , "X-Test" , "X-Secret" ) ) ) ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
) ,
)
assert . Equal ( t , expected , actual )
}
func TestLoadIngressesForwardAuthMissingURL ( t * testing . T ) {
ingresses := [ ] * extensionsv1beta1 . Ingress {
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesAuthType , "forward" ) ,
iRules (
iRule ( iHost ( "foo" ) ,
iPaths (
onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
}
services := [ ] * corev1 . Service {
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
}
endpoints := [ ] * corev1 . Endpoints {
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service1" ) ,
eUID ( "1" ) ,
subset (
eAddresses ( eAddress ( "10.10.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
) ,
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
watchChan : watchChan ,
}
provider := Provider { }
actual , err := provider . loadIngresses ( client )
require . NoError ( t , err , "error loading ingresses" )
expected := buildConfiguration (
backends (
backend ( "foo/bar" ,
lbMethod ( "wrr" ) ,
servers ( ) ,
) ,
) ,
frontends ( ) ,
)
assert . Equal ( t , expected , actual )
}
func TestLoadIngressesForwardAuthWithTLSSecret ( t * testing . T ) {
ingresses := [ ] * extensionsv1beta1 . Ingress {
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesAuthType , "forward" ) ,
iAnnotation ( annotationKubernetesAuthForwardURL , "https://auth.host" ) ,
iAnnotation ( annotationKubernetesAuthForwardTLSSecret , "secret" ) ,
iAnnotation ( annotationKubernetesAuthForwardTLSInsecure , "true" ) ,
iRules (
iRule ( iHost ( "foo" ) ,
iPaths (
onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
}
secrets := [ ] * corev1 . Secret { {
ObjectMeta : metav1 . ObjectMeta {
Name : "secret" ,
UID : "1" ,
Namespace : "testing" ,
} ,
Data : map [ string ] [ ] byte {
"tls.crt" : [ ] byte ( "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----" ) ,
"tls.key" : [ ] byte ( "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----" ) ,
} ,
} }
services := [ ] * corev1 . Service {
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
}
endpoints := [ ] * corev1 . Endpoints {
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service1" ) ,
eUID ( "1" ) ,
subset (
eAddresses ( eAddress ( "10.10.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
) ,
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
secrets : secrets ,
watchChan : watchChan ,
}
provider := Provider { }
actual , err := provider . loadIngresses ( client )
require . NoError ( t , err , "error loading ingresses" )
expected := buildConfiguration (
backends (
backend ( "foo/bar" ,
lbMethod ( "wrr" ) ,
servers (
server ( "http://10.10.0.1:8080" , weight ( 1 ) ) ) ,
) ,
) ,
frontends (
frontend ( "foo/bar" ,
passHostHeader ( ) ,
auth (
forwardAuth ( "https://auth.host" ,
fwdAuthTLS (
"-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----" ,
"-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----" ,
true ) ) ) ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "foo" , "Host:foo" ) ) ,
) ,
) ,
)
assert . Equal ( t , expected , actual )
}
func TestLoadIngressesForwardAuthWithTLSSecretFailures ( t * testing . T ) {
2018-07-06 08:06:04 +00:00
testCases := [ ] struct {
2018-07-02 09:52:04 +00:00
desc string
secretName string
certName string
certData string
keyName string
keyData string
} {
{
desc : "empty certificate and key" ,
secretName : "secret" ,
certName : "" ,
certData : "" ,
keyName : "" ,
keyData : "" ,
} ,
{
desc : "wrong secret name, empty certificate and key" ,
secretName : "wrongSecret" ,
certName : "" ,
certData : "" ,
keyName : "" ,
keyData : "" ,
} ,
{
desc : "empty certificate data" ,
secretName : "secret" ,
certName : "tls.crt" ,
certData : "" ,
keyName : "tls.key" ,
keyData : "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----" ,
} ,
{
desc : "empty key data" ,
secretName : "secret" ,
certName : "tls.crt" ,
certData : "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----" ,
keyName : "tls.key" ,
keyData : "" ,
} ,
{
desc : "wrong cert name" ,
secretName : "secret" ,
certName : "cert.crt" ,
certData : "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE----" ,
keyName : "tls.key" ,
keyData : "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----" ,
} ,
{
desc : "wrong key name" ,
secretName : "secret" ,
certName : "tls.crt" ,
certData : "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----" ,
keyName : "cert.key" ,
keyData : "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----" ,
} ,
}
ingresses := [ ] * extensionsv1beta1 . Ingress {
buildIngress (
iNamespace ( "testing" ) ,
iAnnotation ( annotationKubernetesAuthType , "forward" ) ,
iAnnotation ( annotationKubernetesAuthForwardURL , "https://auth.host" ) ,
iAnnotation ( annotationKubernetesAuthForwardTLSSecret , "secret" ) ,
iRules (
iRule ( iHost ( "foo" ) ,
iPaths (
onePath ( iPath ( "/bar" ) , iBackend ( "service1" , intstr . FromInt ( 80 ) ) ) ) ) ,
) ,
) ,
}
services := [ ] * corev1 . Service {
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
}
endpoints := [ ] * corev1 . Endpoints {
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service1" ) ,
eUID ( "1" ) ,
subset (
eAddresses ( eAddress ( "10.10.0.1" ) ) ,
ePorts ( ePort ( 8080 , "" ) ) ) ,
) ,
}
2018-07-06 08:06:04 +00:00
for _ , test := range testCases {
2018-07-02 09:52:04 +00:00
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
secrets := [ ] * corev1 . Secret { {
ObjectMeta : metav1 . ObjectMeta {
Name : test . secretName ,
UID : "1" ,
Namespace : "testing" ,
} ,
Data : map [ string ] [ ] byte {
test . certName : [ ] byte ( test . certData ) ,
test . keyName : [ ] byte ( test . keyData ) ,
} ,
} }
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
secrets : secrets ,
watchChan : watchChan ,
}
provider := Provider { }
actual , err := provider . loadIngresses ( client )
require . NoError ( t , err , "error loading ingresses" )
expected := buildConfiguration (
backends (
backend ( "foo/bar" ,
lbMethod ( "wrr" ) ,
servers ( ) ,
) ,
) ,
frontends ( ) ,
)
assert . Equal ( t , expected , actual )
} )
2017-04-23 14:17:20 +00:00
}
}
2018-01-07 23:36:03 +00:00
func TestTLSSecretLoad ( t * testing . T ) {
2018-02-14 08:56:04 +00:00
ingresses := [ ] * extensionsv1beta1 . Ingress {
2018-01-07 23:36:03 +00:00
buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesFrontendEntryPoints , "ep1,ep2" ) ,
2018-01-07 23:36:03 +00:00
iRules (
iRule ( iHost ( "example.com" ) , iPaths (
onePath ( iBackend ( "example-com" , intstr . FromInt ( 80 ) ) ) ,
) ) ,
iRule ( iHost ( "example.org" ) , iPaths (
onePath ( iBackend ( "example-org" , intstr . FromInt ( 80 ) ) ) ,
) ) ,
) ,
iTLSes (
iTLS ( "myTlsSecret" ) ,
) ,
) ,
buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesFrontendEntryPoints , "ep3" ) ,
2018-01-07 23:36:03 +00:00
iRules (
iRule ( iHost ( "example.fail" ) , iPaths (
onePath ( iBackend ( "example-fail" , intstr . FromInt ( 80 ) ) ) ,
) ) ,
) ,
iTLSes (
iTLS ( "myUndefinedSecret" ) ,
) ,
) ,
}
2018-02-14 08:56:04 +00:00
services := [ ] * corev1 . Service {
2018-01-07 23:36:03 +00:00
buildService (
sName ( "example-com" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sType ( "ClusterIP" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
buildService (
sName ( "example-org" ) ,
sNamespace ( "testing" ) ,
sUID ( "2" ) ,
sSpec (
clusterIP ( "10.0.0.2" ) ,
sType ( "ClusterIP" ) ,
sPorts ( sPort ( 80 , "http" ) ) ) ,
) ,
}
2018-02-14 08:56:04 +00:00
secrets := [ ] * corev1 . Secret {
2018-01-07 23:36:03 +00:00
{
2018-02-14 08:56:04 +00:00
ObjectMeta : metav1 . ObjectMeta {
2018-01-07 23:36:03 +00:00
Name : "myTlsSecret" ,
UID : "1" ,
Namespace : "testing" ,
} ,
Data : map [ string ] [ ] byte {
"tls.crt" : [ ] byte ( "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----" ) ,
"tls.key" : [ ] byte ( "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----" ) ,
} ,
} ,
}
2018-07-03 08:02:03 +00:00
var endpoints [ ] * corev1 . Endpoints
2018-01-07 23:36:03 +00:00
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
secrets : secrets ,
endpoints : endpoints ,
watchChan : watchChan ,
}
provider := Provider { }
actual , err := provider . loadIngresses ( client )
if err != nil {
t . Fatalf ( "error %+v" , err )
}
expected := buildConfiguration (
backends (
backend ( "example.com" ,
servers ( ) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "example.org" ,
servers ( ) ,
lbMethod ( "wrr" ) ,
) ,
) ,
frontends (
frontend ( "example.com" ,
entryPoints ( "ep1" , "ep2" ) ,
passHostHeader ( ) ,
routes (
route ( "example.com" , "Host:example.com" ) ,
) ,
) ,
frontend ( "example.org" ,
entryPoints ( "ep1" , "ep2" ) ,
passHostHeader ( ) ,
routes (
route ( "example.org" , "Host:example.org" ) ,
) ,
) ,
) ,
2018-01-24 10:57:06 +00:00
tlsesSection (
tlsSection (
2018-01-07 23:36:03 +00:00
tlsEntryPoints ( "ep1" , "ep2" ) ,
certificate (
"-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----" ,
"-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----" ) ,
) ,
) ,
)
assert . Equal ( t , expected , actual )
}
2018-01-24 10:57:06 +00:00
func TestGetTLS ( t * testing . T ) {
2018-01-07 23:36:03 +00:00
testIngressWithoutHostname := buildIngress (
iNamespace ( "testing" ) ,
iRules (
iRule ( iHost ( "ep1.example.com" ) ) ,
iRule ( iHost ( "ep2.example.com" ) ) ,
) ,
iTLSes (
iTLS ( "test-secret" ) ,
) ,
)
2018-07-06 08:06:04 +00:00
testCases := [ ] struct {
2018-01-07 23:36:03 +00:00
desc string
2018-02-14 08:56:04 +00:00
ingress * extensionsv1beta1 . Ingress
2018-01-07 23:36:03 +00:00
client Client
result [ ] * tls . Configuration
errResult string
} {
{
desc : "api client returns error" ,
ingress : testIngressWithoutHostname ,
client : clientMock {
apiSecretError : errors . New ( "api secret error" ) ,
} ,
errResult : "failed to fetch secret testing/test-secret: api secret error" ,
} ,
{
desc : "api client doesn't find secret" ,
ingress : testIngressWithoutHostname ,
client : clientMock { } ,
errResult : "secret testing/test-secret does not exist" ,
} ,
{
desc : "entry 'tls.crt' in secret missing" ,
ingress : testIngressWithoutHostname ,
client : clientMock {
2018-02-14 08:56:04 +00:00
secrets : [ ] * corev1 . Secret {
2018-01-07 23:36:03 +00:00
{
2018-02-14 08:56:04 +00:00
ObjectMeta : metav1 . ObjectMeta {
2018-01-07 23:36:03 +00:00
Name : "test-secret" ,
Namespace : "testing" ,
} ,
Data : map [ string ] [ ] byte {
"tls.key" : [ ] byte ( "tls-key" ) ,
} ,
} ,
} ,
} ,
errResult : "secret testing/test-secret is missing the following TLS data entries: tls.crt" ,
} ,
{
desc : "entry 'tls.key' in secret missing" ,
ingress : testIngressWithoutHostname ,
client : clientMock {
2018-02-14 08:56:04 +00:00
secrets : [ ] * corev1 . Secret {
2018-01-07 23:36:03 +00:00
{
2018-02-14 08:56:04 +00:00
ObjectMeta : metav1 . ObjectMeta {
2018-01-07 23:36:03 +00:00
Name : "test-secret" ,
Namespace : "testing" ,
} ,
Data : map [ string ] [ ] byte {
"tls.crt" : [ ] byte ( "tls-crt" ) ,
} ,
} ,
} ,
} ,
errResult : "secret testing/test-secret is missing the following TLS data entries: tls.key" ,
} ,
{
desc : "secret doesn't provide any of the required fields" ,
ingress : testIngressWithoutHostname ,
client : clientMock {
2018-02-14 08:56:04 +00:00
secrets : [ ] * corev1 . Secret {
2018-01-07 23:36:03 +00:00
{
2018-02-14 08:56:04 +00:00
ObjectMeta : metav1 . ObjectMeta {
2018-01-07 23:36:03 +00:00
Name : "test-secret" ,
Namespace : "testing" ,
} ,
Data : map [ string ] [ ] byte { } ,
} ,
} ,
} ,
errResult : "secret testing/test-secret is missing the following TLS data entries: tls.crt, tls.key" ,
} ,
{
desc : "add certificates to the configuration" ,
ingress : buildIngress (
iNamespace ( "testing" ) ,
iRules (
iRule ( iHost ( "ep1.example.com" ) ) ,
iRule ( iHost ( "ep2.example.com" ) ) ,
iRule ( iHost ( "ep3.example.com" ) ) ,
) ,
iTLSes (
iTLS ( "test-secret" ) ,
iTLS ( "test-secret" ) ,
) ,
) ,
client : clientMock {
2018-02-14 08:56:04 +00:00
secrets : [ ] * corev1 . Secret {
2018-01-07 23:36:03 +00:00
{
2018-02-14 08:56:04 +00:00
ObjectMeta : metav1 . ObjectMeta {
2018-01-07 23:36:03 +00:00
Name : "test-secret" ,
Namespace : "testing" ,
} ,
Data : map [ string ] [ ] byte {
"tls.crt" : [ ] byte ( "tls-crt" ) ,
"tls.key" : [ ] byte ( "tls-key" ) ,
} ,
} ,
} ,
} ,
result : [ ] * tls . Configuration {
{
Certificate : & tls . Certificate {
CertFile : tls . FileOrContent ( "tls-crt" ) ,
KeyFile : tls . FileOrContent ( "tls-key" ) ,
} ,
} ,
{
Certificate : & tls . Certificate {
CertFile : tls . FileOrContent ( "tls-crt" ) ,
KeyFile : tls . FileOrContent ( "tls-key" ) ,
} ,
} ,
} ,
} ,
{
desc : "pass the endpoints defined in the annotation to the certificate" ,
ingress : buildIngress (
iNamespace ( "testing" ) ,
2018-01-26 12:29:42 +00:00
iAnnotation ( annotationKubernetesFrontendEntryPoints , "https,api-secure" ) ,
2018-01-07 23:36:03 +00:00
iRules ( iRule ( iHost ( "example.com" ) ) ) ,
iTLSes ( iTLS ( "test-secret" ) ) ,
) ,
client : clientMock {
2018-02-14 08:56:04 +00:00
secrets : [ ] * corev1 . Secret {
2018-01-07 23:36:03 +00:00
{
2018-02-14 08:56:04 +00:00
ObjectMeta : metav1 . ObjectMeta {
2018-01-07 23:36:03 +00:00
Name : "test-secret" ,
Namespace : "testing" ,
} ,
Data : map [ string ] [ ] byte {
"tls.crt" : [ ] byte ( "tls-crt" ) ,
"tls.key" : [ ] byte ( "tls-key" ) ,
} ,
} ,
} ,
} ,
result : [ ] * tls . Configuration {
{
EntryPoints : [ ] string { "https" , "api-secure" } ,
Certificate : & tls . Certificate {
CertFile : tls . FileOrContent ( "tls-crt" ) ,
KeyFile : tls . FileOrContent ( "tls-key" ) ,
} ,
} ,
} ,
} ,
}
2018-07-06 08:06:04 +00:00
for _ , test := range testCases {
2018-01-07 23:36:03 +00:00
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
2018-01-24 10:57:06 +00:00
tlsConfigs , err := getTLS ( test . ingress , test . client )
2018-01-07 23:36:03 +00:00
if test . errResult != "" {
assert . EqualError ( t , err , test . errResult )
} else {
assert . Nil ( t , err )
assert . Equal ( t , test . result , tlsConfigs )
}
} )
}
}
2018-04-16 12:44:04 +00:00
func TestMultiPortServices ( t * testing . T ) {
ingresses := [ ] * extensionsv1beta1 . Ingress {
buildIngress (
iNamespace ( "testing" ) ,
iRules (
iRule ( iPaths (
onePath ( iPath ( "/cheddar" ) , iBackend ( "service" , intstr . FromString ( "cheddar" ) ) ) ,
onePath ( iPath ( "/stilton" ) , iBackend ( "service" , intstr . FromString ( "stilton" ) ) ) ,
) ) ,
) ,
) ,
}
services := [ ] * corev1 . Service {
buildService (
sName ( "service" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "cheddar" ) ) ,
sPorts ( sPort ( 81 , "stilton" ) ) ,
) ,
) ,
}
endpoints := [ ] * corev1 . Endpoints {
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service" ) ,
eUID ( "1" ) ,
subset (
eAddresses (
eAddress ( "10.10.0.1" ) ,
eAddress ( "10.10.0.2" ) ,
) ,
ePorts ( ePort ( 8080 , "cheddar" ) ) ,
) ,
subset (
eAddresses (
eAddress ( "10.20.0.1" ) ,
eAddress ( "10.20.0.2" ) ,
) ,
ePorts ( ePort ( 8081 , "stilton" ) ) ,
) ,
) ,
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
watchChan : watchChan ,
}
provider := Provider { }
actual , err := provider . loadIngresses ( client )
require . NoError ( t , err , "error loading ingresses" )
expected := buildConfiguration (
backends (
backend ( "/cheddar" ,
lbMethod ( "wrr" ) ,
servers (
server ( "http://10.10.0.1:8080" , weight ( 1 ) ) ,
server ( "http://10.10.0.2:8080" , weight ( 1 ) ) ,
) ,
) ,
backend ( "/stilton" ,
lbMethod ( "wrr" ) ,
servers (
server ( "http://10.20.0.1:8081" , weight ( 1 ) ) ,
server ( "http://10.20.0.2:8081" , weight ( 1 ) ) ,
) ,
) ,
) ,
frontends (
frontend ( "/cheddar" ,
passHostHeader ( ) ,
routes ( route ( "/cheddar" , "PathPrefix:/cheddar" ) ) ,
) ,
frontend ( "/stilton" ,
passHostHeader ( ) ,
routes ( route ( "/stilton" , "PathPrefix:/stilton" ) ) ,
) ,
) ,
)
assert . Equal ( t , expected , actual )
}
2018-05-18 12:12:03 +00:00
func TestProviderUpdateIngressStatus ( t * testing . T ) {
testCases := [ ] struct {
desc string
ingressEndpoint * IngressEndpoint
apiServiceError error
apiIngressStatusError error
expectedError bool
} {
{
desc : "without IngressEndpoint configuration" ,
expectedError : false ,
} ,
{
desc : "without any IngressEndpoint option" ,
ingressEndpoint : & IngressEndpoint { } ,
expectedError : true ,
} ,
{
desc : "PublishedService - invalid format" ,
ingressEndpoint : & IngressEndpoint {
PublishedService : "foo" ,
} ,
expectedError : true ,
} ,
{
desc : "PublishedService - missing service" ,
ingressEndpoint : & IngressEndpoint {
PublishedService : "foo/bar" ,
} ,
expectedError : true ,
} ,
{
desc : "PublishedService - get service error" ,
ingressEndpoint : & IngressEndpoint {
PublishedService : "foo/bar" ,
} ,
apiServiceError : errors . New ( "error" ) ,
expectedError : true ,
} ,
{
desc : "PublishedService - Skipping empty LoadBalancerIngress" ,
ingressEndpoint : & IngressEndpoint {
PublishedService : "testing/service-empty-status" ,
} ,
expectedError : false ,
} ,
{
desc : "PublishedService - with update error" ,
ingressEndpoint : & IngressEndpoint {
PublishedService : "testing/service" ,
} ,
apiIngressStatusError : errors . New ( "error" ) ,
expectedError : true ,
} ,
{
desc : "PublishedService - right service" ,
ingressEndpoint : & IngressEndpoint {
PublishedService : "testing/service" ,
} ,
expectedError : false ,
} ,
{
desc : "IP - valid" ,
ingressEndpoint : & IngressEndpoint {
IP : "127.0.0.1" ,
} ,
expectedError : false ,
} ,
{
desc : "IP - with update error" ,
ingressEndpoint : & IngressEndpoint {
IP : "127.0.0.1" ,
} ,
apiIngressStatusError : errors . New ( "error" ) ,
expectedError : true ,
} ,
{
desc : "hostname - valid" ,
ingressEndpoint : & IngressEndpoint {
Hostname : "foo" ,
} ,
expectedError : false ,
} ,
{
desc : "hostname - with update error" ,
ingressEndpoint : & IngressEndpoint {
Hostname : "foo" ,
} ,
apiIngressStatusError : errors . New ( "error" ) ,
expectedError : true ,
} ,
}
for _ , test := range testCases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
p := & Provider {
IngressEndpoint : test . ingressEndpoint ,
}
services := [ ] * corev1 . Service {
buildService (
sName ( "service-empty-status" ) ,
sNamespace ( "testing" ) ,
sLoadBalancerStatus ( ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
buildService (
sName ( "service" ) ,
sNamespace ( "testing" ) ,
sLoadBalancerStatus ( sLoadBalancerIngress ( "127.0.0.1" , "" ) ) ,
sUID ( "2" ) ,
sSpec (
clusterIP ( "10.0.0.2" ) ,
sPorts ( sPort ( 80 , "" ) ) ) ,
) ,
}
client := clientMock {
services : services ,
apiServiceError : test . apiServiceError ,
apiIngressStatusError : test . apiIngressStatusError ,
}
i := & extensionsv1beta1 . Ingress { }
err := p . updateIngressStatus ( i , client )
if test . expectedError {
assert . Error ( t , err )
} else {
assert . NoError ( t , err )
}
} )
}
2018-07-01 09:26:03 +00:00
}
func TestPercentageWeightServiceAnnotation ( t * testing . T ) {
ingresses := [ ] * extensionsv1beta1 . Ingress {
buildIngress (
iAnnotation ( annotationKubernetesServiceWeights , `
service1 : 10 %
` ) ,
iNamespace ( "testing" ) ,
iRules (
iRule (
iHost ( "host1" ) ,
iPaths (
onePath ( iPath ( "/foo" ) , iBackend ( "service1" , intstr . FromString ( "8080" ) ) ) ,
onePath ( iPath ( "/foo" ) , iBackend ( "service2" , intstr . FromString ( "7070" ) ) ) ,
onePath ( iPath ( "/bar" ) , iBackend ( "service2" , intstr . FromString ( "7070" ) ) ) ,
) ) ,
) ,
) ,
}
services := [ ] * corev1 . Service {
buildService (
sName ( "service1" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 8080 , "" ) ) ,
) ,
) ,
buildService (
sName ( "service2" ) ,
sNamespace ( "testing" ) ,
sUID ( "1" ) ,
sSpec (
clusterIP ( "10.0.0.1" ) ,
sPorts ( sPort ( 7070 , "" ) ) ,
) ,
) ,
}
endpoints := [ ] * corev1 . Endpoints {
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service1" ) ,
eUID ( "1" ) ,
subset (
eAddresses (
eAddress ( "10.10.0.1" ) ,
eAddress ( "10.10.0.2" ) ,
) ,
ePorts ( ePort ( 8080 , "" ) ) ,
) ,
) ,
buildEndpoint (
eNamespace ( "testing" ) ,
eName ( "service2" ) ,
eUID ( "1" ) ,
subset (
eAddresses (
eAddress ( "10.10.0.3" ) ,
eAddress ( "10.10.0.4" ) ,
) ,
ePorts ( ePort ( 7070 , "" ) ) ,
) ,
) ,
}
watchChan := make ( chan interface { } )
client := clientMock {
ingresses : ingresses ,
services : services ,
endpoints : endpoints ,
watchChan : watchChan ,
}
provider := Provider { }
actual , err := provider . loadIngresses ( client )
require . NoError ( t , err , "error loading ingresses" )
expected := buildConfiguration (
backends (
backend ( "host1/foo" ,
servers (
server ( "http://10.10.0.1:8080" , weight ( int ( newPercentageValueFromFloat64 ( 0.05 ) ) ) ) ,
server ( "http://10.10.0.2:8080" , weight ( int ( newPercentageValueFromFloat64 ( 0.05 ) ) ) ) ,
server ( "http://10.10.0.3:7070" , weight ( int ( newPercentageValueFromFloat64 ( 0.45 ) ) ) ) ,
server ( "http://10.10.0.4:7070" , weight ( int ( newPercentageValueFromFloat64 ( 0.45 ) ) ) ) ,
) ,
lbMethod ( "wrr" ) ,
) ,
backend ( "host1/bar" ,
servers (
server ( "http://10.10.0.3:7070" , weight ( int ( newPercentageValueFromFloat64 ( 0.5 ) ) ) ) ,
server ( "http://10.10.0.4:7070" , weight ( int ( newPercentageValueFromFloat64 ( 0.5 ) ) ) ) ,
) ,
lbMethod ( "wrr" ) ,
) ,
) ,
frontends (
frontend ( "host1/bar" ,
passHostHeader ( ) ,
routes (
route ( "/bar" , "PathPrefix:/bar" ) ,
route ( "host1" , "Host:host1" ) ) ,
) ,
frontend ( "host1/foo" ,
passHostHeader ( ) ,
routes (
route ( "/foo" , "PathPrefix:/foo" ) ,
route ( "host1" , "Host:host1" ) ) ,
) ,
) ,
)
2018-05-18 12:12:03 +00:00
2018-07-01 09:26:03 +00:00
assert . Equal ( t , expected , actual , "error loading percentage weight annotation" )
2018-05-18 12:12:03 +00:00
}
2018-06-19 20:10:03 +00:00
func TestProviderNewK8sInClusterClient ( t * testing . T ) {
p := Provider { }
os . Setenv ( "KUBERNETES_SERVICE_HOST" , "localhost" )
os . Setenv ( "KUBERNETES_SERVICE_PORT" , "443" )
defer os . Clearenv ( )
_ , err := p . newK8sClient ( "" )
assert . EqualError ( t , err , "failed to create in-cluster configuration: open /var/run/secrets/kubernetes.io/serviceaccount/token: no such file or directory" )
}
func TestProviderNewK8sInClusterClientFailLabelSel ( t * testing . T ) {
p := Provider { }
os . Setenv ( "KUBERNETES_SERVICE_HOST" , "localhost" )
os . Setenv ( "KUBERNETES_SERVICE_PORT" , "443" )
defer os . Clearenv ( )
_ , err := p . newK8sClient ( "%" )
assert . EqualError ( t , err , "invalid ingress label selector: \"%\"" )
}
func TestProviderNewK8sOutOfClusterClient ( t * testing . T ) {
p := Provider { }
p . Endpoint = "localhost"
_ , err := p . newK8sClient ( "" )
assert . NoError ( t , err )
}