2015-10-26 01:01:02 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2015 The Kubernetes Authors .
2015-10-26 01:01:02 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2017-08-01 11:45:33 +00:00
package network
2015-10-26 01:01:02 +00:00
import (
"fmt"
2015-11-19 01:41:21 +00:00
"path/filepath"
2015-10-26 01:01:02 +00:00
"time"
2017-06-22 18:24:23 +00:00
rbacv1beta1 "k8s.io/api/rbac/v1beta1"
2017-10-18 22:38:05 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/runtime/schema"
2017-10-18 22:38:05 +00:00
"k8s.io/apimachinery/pkg/util/wait"
2017-01-16 11:43:56 +00:00
"k8s.io/apiserver/pkg/authentication/serviceaccount"
2016-04-07 17:21:31 +00:00
"k8s.io/kubernetes/test/e2e/framework"
2015-10-26 01:01:02 +00:00
. "github.com/onsi/ginkgo"
2016-12-03 02:08:52 +00:00
. "github.com/onsi/gomega"
2015-10-26 01:01:02 +00:00
)
2017-10-17 23:57:07 +00:00
const (
2017-10-18 23:44:48 +00:00
NEGAnnotation = "alpha.cloud.google.com/load-balancer-neg"
NEGUpdateTimeout = 2 * time . Minute
2017-10-17 23:57:07 +00:00
)
2017-08-01 11:45:33 +00:00
var _ = SIGDescribe ( "Loadbalancing: L7" , func ( ) {
2016-05-31 19:12:58 +00:00
defer GinkgoRecover ( )
2016-07-29 08:01:41 +00:00
var (
ns string
2017-02-23 02:08:37 +00:00
jig * framework . IngressTestJig
conformanceTests [ ] framework . IngressConformanceTests
2017-06-07 00:29:36 +00:00
cloudConfig framework . CloudConfig
2016-07-29 08:01:41 +00:00
)
2016-05-31 19:12:58 +00:00
f := framework . NewDefaultFramework ( "ingress" )
2015-11-08 00:48:11 +00:00
2016-05-31 19:12:58 +00:00
BeforeEach ( func ( ) {
f . BeforeEach ( )
2017-02-23 02:08:37 +00:00
jig = framework . NewIngressTestJig ( f . ClientSet )
2016-05-31 19:12:58 +00:00
ns = f . Namespace . Name
2017-06-07 00:29:36 +00:00
cloudConfig = framework . TestContext . CloudConfig
2016-12-15 17:52:14 +00:00
// this test wants powerful permissions. Since the namespace names are unique, we can leave this
// lying around so we don't have to race any caches
2017-07-26 14:36:43 +00:00
framework . BindClusterRole ( jig . Client . RbacV1beta1 ( ) , "cluster-admin" , f . Namespace . Name ,
2017-01-09 17:24:21 +00:00
rbacv1beta1 . Subject { Kind : rbacv1beta1 . ServiceAccountKind , Namespace : f . Namespace . Name , Name : "default" } )
2016-12-15 17:52:14 +00:00
2017-02-23 02:08:37 +00:00
err := framework . WaitForAuthorizationUpdate ( jig . Client . AuthorizationV1beta1 ( ) ,
2016-12-15 17:52:14 +00:00
serviceaccount . MakeUsername ( f . Namespace . Name , "default" ) ,
"" , "create" , schema . GroupResource { Resource : "pods" } , true )
framework . ExpectNoError ( err )
2016-05-31 19:12:58 +00:00
} )
2016-02-17 23:46:25 +00:00
2016-05-31 19:12:58 +00:00
// Before enabling this loadbalancer test in any other test list you must
// make sure the associated project has enough quota. At the time of this
// writing a GCE project is allowed 3 backend services by default. This
// test requires at least 5.
//
// Slow by design ~10m for each "It" block dominated by loadbalancer setup time
// TODO: write similar tests for nginx, haproxy and AWS Ingress.
2017-08-21 18:17:02 +00:00
Describe ( "GCE [Slow] [Feature:Ingress]" , func ( ) {
2017-02-23 02:08:37 +00:00
var gceController * framework . GCEIngressController
2016-05-31 19:12:58 +00:00
// Platform specific setup
BeforeEach ( func ( ) {
framework . SkipUnlessProviderIs ( "gce" , "gke" )
By ( "Initializing gce controller" )
2017-02-23 02:08:37 +00:00
gceController = & framework . GCEIngressController {
Ns : ns ,
Client : jig . Client ,
Cloud : framework . TestContext . CloudConfig ,
2016-09-07 00:18:48 +00:00
}
2017-02-23 02:08:37 +00:00
gceController . Init ( )
2016-05-31 19:12:58 +00:00
} )
2015-10-26 01:01:02 +00:00
2016-05-31 19:12:58 +00:00
// Platform specific cleanup
AfterEach ( func ( ) {
if CurrentGinkgoTestDescription ( ) . Failed {
2017-01-11 12:51:26 +00:00
framework . DescribeIng ( ns )
2016-05-31 19:12:58 +00:00
}
2017-02-23 02:08:37 +00:00
if jig . Ingress == nil {
2016-05-31 19:12:58 +00:00
By ( "No ingress created, no cleanup necessary" )
return
}
By ( "Deleting ingress" )
2017-06-29 19:05:32 +00:00
jig . TryDeleteIngress ( )
2016-05-31 19:12:58 +00:00
By ( "Cleaning up cloud resources" )
2017-02-23 02:08:37 +00:00
framework . CleanupGCEIngressController ( gceController )
2016-05-31 19:12:58 +00:00
} )
2015-11-19 01:41:21 +00:00
2016-05-31 19:12:58 +00:00
It ( "should conform to Ingress spec" , func ( ) {
2017-10-17 23:57:07 +00:00
conformanceTests = framework . CreateIngressComformanceTests ( jig , ns , map [ string ] string { } )
2016-05-31 19:12:58 +00:00
for _ , t := range conformanceTests {
2017-02-23 02:08:37 +00:00
By ( t . EntryLog )
t . Execute ( )
By ( t . ExitLog )
jig . WaitForIngress ( true )
2016-05-31 19:12:58 +00:00
}
} )
2015-11-19 01:41:21 +00:00
2017-02-15 20:24:38 +00:00
It ( "should create ingress with given static-ip" , func ( ) {
2017-02-23 02:08:37 +00:00
// ip released when the rest of lb resources are deleted in CleanupGCEIngressController
ip := gceController . CreateStaticIP ( ns )
2016-05-31 19:12:58 +00:00
By ( fmt . Sprintf ( "allocated static ip %v: %v through the GCE cloud provider" , ns , ip ) )
2017-02-23 02:08:37 +00:00
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "static-ip" ) , ns , map [ string ] string {
2016-05-31 19:12:58 +00:00
"kubernetes.io/ingress.global-static-ip-name" : ns ,
"kubernetes.io/ingress.allow-http" : "false" ,
2017-10-17 23:57:07 +00:00
} , map [ string ] string { } )
2016-05-31 19:12:58 +00:00
By ( "waiting for Ingress to come up with ip: " + ip )
2017-02-23 02:08:37 +00:00
httpClient := framework . BuildInsecureClient ( framework . IngressReqTimeout )
framework . ExpectNoError ( framework . PollURL ( fmt . Sprintf ( "https://%v/" , ip ) , "" , framework . LoadBalancerPollTimeout , jig . PollInterval , httpClient , false ) )
2016-05-31 19:12:58 +00:00
By ( "should reject HTTP traffic" )
2017-02-23 02:08:37 +00:00
framework . ExpectNoError ( framework . PollURL ( fmt . Sprintf ( "http://%v/" , ip ) , "" , framework . LoadBalancerPollTimeout , jig . PollInterval , httpClient , true ) )
2016-05-31 19:12:58 +00:00
2016-12-03 02:08:52 +00:00
By ( "should have correct firewall rule for ingress" )
2017-02-23 02:08:37 +00:00
fw := gceController . GetFirewallRule ( )
2017-06-30 00:32:49 +00:00
nodeTags := [ ] string { cloudConfig . NodeTag }
if framework . TestContext . Provider != "gce" {
// nodeTags would be different in GKE.
nodeTags = framework . GetNodeTags ( jig . Client , cloudConfig )
}
expFw := jig . ConstructFirewallForIngress ( gceController , nodeTags )
2016-12-03 02:08:52 +00:00
// Passed the last argument as `true` to verify the backend ports is a subset
// of the allowed ports in firewall rule, given there may be other existing
// ingress resources and backends we are not aware of.
2017-02-23 02:08:37 +00:00
Expect ( framework . VerifyFirewallRule ( fw , expFw , gceController . Cloud . Network , true ) ) . NotTo ( HaveOccurred ( ) )
2016-12-03 02:08:52 +00:00
2016-05-31 19:12:58 +00:00
// TODO: uncomment the restart test once we have a way to synchronize
// and know that the controller has resumed watching. If we delete
// the ingress before the controller is ready we will leak.
// By("restaring glbc")
// restarter := NewRestartConfig(
// framework.GetMasterHost(), "glbc", glbcHealthzPort, restartPollInterval, restartTimeout)
// restarter.restart()
// By("should continue serving on provided static-ip for 30 seconds")
2017-02-16 04:59:26 +00:00
// framework.ExpectNoError(jig.verifyURL(fmt.Sprintf("https://%v/", ip), "", 30, 1*time.Second, httpClient))
2016-05-31 19:12:58 +00:00
} )
2016-01-01 12:41:27 +00:00
2016-05-31 19:12:58 +00:00
// TODO: Implement a multizone e2e that verifies traffic reaches each
// zone based on pod labels.
} )
2017-10-17 23:57:07 +00:00
Describe ( "GCE [Slow] [Feature:NEG]" , func ( ) {
var gceController * framework . GCEIngressController
// Platform specific setup
BeforeEach ( func ( ) {
framework . SkipUnlessProviderIs ( "gce" , "gke" )
By ( "Initializing gce controller" )
gceController = & framework . GCEIngressController {
Ns : ns ,
Client : jig . Client ,
Cloud : framework . TestContext . CloudConfig ,
}
gceController . Init ( )
} )
// Platform specific cleanup
AfterEach ( func ( ) {
if CurrentGinkgoTestDescription ( ) . Failed {
framework . DescribeIng ( ns )
}
if jig . Ingress == nil {
By ( "No ingress created, no cleanup necessary" )
return
}
By ( "Deleting ingress" )
jig . TryDeleteIngress ( )
By ( "Cleaning up cloud resources" )
framework . CleanupGCEIngressController ( gceController )
} )
It ( "should conform to Ingress spec" , func ( ) {
jig . PollInterval = 5 * time . Second
conformanceTests = framework . CreateIngressComformanceTests ( jig , ns , map [ string ] string {
NEGAnnotation : "true" ,
} )
for _ , t := range conformanceTests {
By ( t . EntryLog )
t . Execute ( )
By ( t . ExitLog )
jig . WaitForIngress ( true )
usingNeg , err := gceController . BackendServiceUsingNEG ( jig . GetIngressNodePorts ( false ) )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
Expect ( usingNeg ) . To ( BeTrue ( ) )
}
} )
2017-10-18 22:38:05 +00:00
It ( "should be able to switch between IG and NEG modes" , func ( ) {
var err error
By ( "Create a basic HTTP ingress using NEG" )
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "neg" ) , ns , map [ string ] string { } , map [ string ] string { } )
jig . WaitForIngress ( true )
usingNEG , err := gceController . BackendServiceUsingNEG ( jig . GetIngressNodePorts ( false ) )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
Expect ( usingNEG ) . To ( BeTrue ( ) )
By ( "Switch backend service to use IG" )
svcList , err := f . ClientSet . CoreV1 ( ) . Services ( ns ) . List ( metav1 . ListOptions { } )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
for _ , svc := range svcList . Items {
svc . Annotations [ NEGAnnotation ] = "false"
_ , err = f . ClientSet . CoreV1 ( ) . Services ( ns ) . Update ( & svc )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
wait . Poll ( 5 * time . Second , framework . LoadBalancerPollTimeout , func ( ) ( bool , error ) {
return gceController . BackendServiceUsingIG ( jig . GetIngressNodePorts ( true ) )
} )
jig . WaitForIngress ( true )
By ( "Switch backend service to use NEG" )
svcList , err = f . ClientSet . CoreV1 ( ) . Services ( ns ) . List ( metav1 . ListOptions { } )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
for _ , svc := range svcList . Items {
svc . Annotations [ NEGAnnotation ] = "true"
_ , err = f . ClientSet . CoreV1 ( ) . Services ( ns ) . Update ( & svc )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
wait . Poll ( 5 * time . Second , framework . LoadBalancerPollTimeout , func ( ) ( bool , error ) {
return gceController . BackendServiceUsingNEG ( jig . GetIngressNodePorts ( false ) )
} )
jig . WaitForIngress ( true )
} )
2017-10-18 23:44:48 +00:00
It ( "should sync endpoints to NEG" , func ( ) {
name := "hostname"
scaleAndValidateNEG := func ( num int ) {
scale , err := f . ClientSet . ExtensionsV1beta1 ( ) . Deployments ( ns ) . GetScale ( name , metav1 . GetOptions { } )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if scale . Spec . Replicas != int32 ( num ) {
scale . Spec . Replicas = int32 ( num )
_ , err = f . ClientSet . ExtensionsV1beta1 ( ) . Deployments ( ns ) . UpdateScale ( name , scale )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
wait . Poll ( 5 * time . Second , NEGUpdateTimeout , func ( ) ( bool , error ) {
res , err := jig . GetDistinctResponseFromIngress ( )
if err != nil {
return false , err
}
return res . Len ( ) == num , err
} )
}
By ( "Create a basic HTTP ingress using NEG" )
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "neg" ) , ns , map [ string ] string { } , map [ string ] string { } )
jig . WaitForIngress ( true )
usingNEG , err := gceController . BackendServiceUsingNEG ( jig . GetIngressNodePorts ( false ) )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
Expect ( usingNEG ) . To ( BeTrue ( ) )
// initial replicas number is 1
scaleAndValidateNEG ( 1 )
By ( "Scale up number of backends to 5" )
scaleAndValidateNEG ( 5 )
By ( "Scale down number of backends to 3" )
scaleAndValidateNEG ( 3 )
By ( "Scale up number of backends to 6" )
scaleAndValidateNEG ( 6 )
By ( "Scale down number of backends to 2" )
scaleAndValidateNEG ( 3 )
} )
2017-10-17 23:57:07 +00:00
} )
2016-08-22 22:15:12 +00:00
// Time: borderline 5m, slow by design
2017-08-21 18:17:02 +00:00
Describe ( "[Slow] Nginx" , func ( ) {
2017-02-23 02:08:37 +00:00
var nginxController * framework . NginxIngressController
2016-08-22 22:15:12 +00:00
BeforeEach ( func ( ) {
framework . SkipUnlessProviderIs ( "gce" , "gke" )
By ( "Initializing nginx controller" )
2017-02-23 02:08:37 +00:00
jig . Class = "nginx"
nginxController = & framework . NginxIngressController { Ns : ns , Client : jig . Client }
2016-08-22 22:15:12 +00:00
// TODO: This test may fail on other platforms. We can simply skip it
// but we want to allow easy testing where a user might've hand
// configured firewalls.
if framework . ProviderIs ( "gce" , "gke" ) {
2017-02-23 02:08:37 +00:00
framework . ExpectNoError ( framework . GcloudComputeResourceCreate ( "firewall-rules" , fmt . Sprintf ( "ingress-80-443-%v" , ns ) , framework . TestContext . CloudConfig . ProjectID , "--allow" , "tcp:80,tcp:443" , "--network" , framework . TestContext . CloudConfig . Network ) )
2016-08-22 22:15:12 +00:00
} else {
framework . Logf ( "WARNING: Not running on GCE/GKE, cannot create firewall rules for :80, :443. Assuming traffic can reach the external ips of all nodes in cluster on those ports." )
}
2017-02-23 02:08:37 +00:00
nginxController . Init ( )
2016-08-22 22:15:12 +00:00
} )
AfterEach ( func ( ) {
if framework . ProviderIs ( "gce" , "gke" ) {
2017-02-23 02:08:37 +00:00
framework . ExpectNoError ( framework . GcloudComputeResourceDelete ( "firewall-rules" , fmt . Sprintf ( "ingress-80-443-%v" , ns ) , framework . TestContext . CloudConfig . ProjectID ) )
2016-08-22 22:15:12 +00:00
}
if CurrentGinkgoTestDescription ( ) . Failed {
2017-01-11 12:51:26 +00:00
framework . DescribeIng ( ns )
2016-08-22 22:15:12 +00:00
}
2017-02-23 02:08:37 +00:00
if jig . Ingress == nil {
2016-08-22 22:15:12 +00:00
By ( "No ingress created, no cleanup necessary" )
return
}
By ( "Deleting ingress" )
2017-06-29 19:05:32 +00:00
jig . TryDeleteIngress ( )
2016-08-22 22:15:12 +00:00
} )
It ( "should conform to Ingress spec" , func ( ) {
2016-12-05 20:34:05 +00:00
// Poll more frequently to reduce e2e completion time.
// This test runs in presubmit.
2017-02-23 02:08:37 +00:00
jig . PollInterval = 5 * time . Second
2017-10-17 23:57:07 +00:00
conformanceTests = framework . CreateIngressComformanceTests ( jig , ns , map [ string ] string { } )
2016-08-22 22:15:12 +00:00
for _ , t := range conformanceTests {
2017-02-23 02:08:37 +00:00
By ( t . EntryLog )
t . Execute ( )
By ( t . ExitLog )
jig . WaitForIngress ( false )
2016-08-22 22:15:12 +00:00
}
} )
} )
2016-05-31 19:12:58 +00:00
} )