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 (
2018-06-21 00:12:32 +00:00
"encoding/json"
2015-10-26 01:01:02 +00:00
"fmt"
2018-02-15 02:39:10 +00:00
"net/http"
2015-11-19 01:41:21 +00:00
"path/filepath"
2018-01-16 22:00:54 +00:00
"strings"
2015-10-26 01:01:02 +00:00
"time"
2018-01-27 00:35:05 +00:00
compute "google.golang.org/api/compute/v1"
2018-01-23 00:25:17 +00:00
extensions "k8s.io/api/extensions/v1beta1"
2017-06-22 18:24:23 +00:00
rbacv1beta1 "k8s.io/api/rbac/v1beta1"
2018-01-27 00:35:05 +00:00
"k8s.io/apimachinery/pkg/api/errors"
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"
2018-01-23 00:25:17 +00:00
"k8s.io/apimachinery/pkg/util/intstr"
2018-03-29 02:17:44 +00:00
"k8s.io/apimachinery/pkg/util/uuid"
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"
2018-01-16 22:00:54 +00:00
gcecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
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-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 ( ) {
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
}
2018-02-06 21:51:32 +00:00
err := gceController . Init ( )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
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" )
2018-02-06 21:51:32 +00:00
Expect ( gceController . CleanupGCEIngressController ( ) ) . NotTo ( HaveOccurred ( ) )
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 ) )
2018-04-03 06:44:53 +00:00
executeStaticIPHttpsOnlyTest ( f , jig , ns , ip )
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
2018-01-23 00:25:17 +00:00
It ( "should update ingress while sync failures occur on other ingresses" , func ( ) {
By ( "Creating ingresses that would fail on sync." )
ingFailTLSBackend := & extensions . Ingress {
ObjectMeta : metav1 . ObjectMeta {
Name : "ing-fail-on-tls-backend" ,
} ,
Spec : extensions . IngressSpec {
TLS : [ ] extensions . IngressTLS {
{ SecretName : "tls-secret-notexist" } ,
} ,
Backend : & extensions . IngressBackend {
ServiceName : "echoheaders-notexist" ,
ServicePort : intstr . IntOrString {
Type : intstr . Int ,
IntVal : 80 ,
} ,
} ,
} ,
}
_ , err := jig . Client . ExtensionsV1beta1 ( ) . Ingresses ( ns ) . Create ( ingFailTLSBackend )
defer func ( ) {
if err := jig . Client . ExtensionsV1beta1 ( ) . Ingresses ( ns ) . Delete ( ingFailTLSBackend . Name , nil ) ; err != nil {
framework . Logf ( "Failed to delete ingress %s: %v" , ingFailTLSBackend . Name , err )
}
} ( )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
ingFailRules := & extensions . Ingress {
ObjectMeta : metav1 . ObjectMeta {
Name : "ing-fail-on-rules" ,
} ,
Spec : extensions . IngressSpec {
Rules : [ ] extensions . IngressRule {
{
Host : "foo.bar.com" ,
IngressRuleValue : extensions . IngressRuleValue {
HTTP : & extensions . HTTPIngressRuleValue {
Paths : [ ] extensions . HTTPIngressPath {
{
Path : "/foo" ,
Backend : extensions . IngressBackend {
ServiceName : "echoheaders-notexist" ,
ServicePort : intstr . IntOrString {
Type : intstr . Int ,
IntVal : 80 ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
}
_ , err = jig . Client . ExtensionsV1beta1 ( ) . Ingresses ( ns ) . Create ( ingFailRules )
defer func ( ) {
if err := jig . Client . ExtensionsV1beta1 ( ) . Ingresses ( ns ) . Delete ( ingFailRules . Name , nil ) ; err != nil {
framework . Logf ( "Failed to delete ingress %s: %v" , ingFailRules . Name , err )
}
} ( )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
By ( "Creating a basic HTTP ingress and wait for it to come up" )
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "http" ) , ns , nil , nil )
jig . WaitForIngress ( true )
By ( "Updating the path on ingress and wait for it to take effect" )
jig . Update ( func ( ing * extensions . Ingress ) {
updatedRule := extensions . IngressRule {
Host : "ingress.test.com" ,
IngressRuleValue : extensions . IngressRuleValue {
HTTP : & extensions . HTTPIngressRuleValue {
Paths : [ ] extensions . HTTPIngressPath {
{
Path : "/test" ,
// Copy backend from the first rule.
Backend : ing . Spec . Rules [ 0 ] . HTTP . Paths [ 0 ] . Backend ,
} ,
} ,
} ,
} ,
}
// Replace the first rule.
ing . Spec . Rules [ 0 ] = updatedRule
} )
// Wait for change to take effect on the updated ingress.
jig . WaitForIngress ( false )
} )
2018-01-16 22:00:54 +00:00
It ( "should not reconcile manually modified health check for ingress" , func ( ) {
By ( "Creating a basic HTTP ingress and wait for it to come up." )
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "http" ) , ns , nil , nil )
jig . WaitForIngress ( true )
// Get cluster UID.
clusterID , err := framework . GetClusterID ( f . ClientSet )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2018-02-01 22:18:43 +00:00
// Get the related nodeports.
nodePorts := jig . GetIngressNodePorts ( false )
Expect ( len ( nodePorts ) ) . ToNot ( Equal ( 0 ) )
2018-01-16 22:00:54 +00:00
// Filter health check using cluster UID as the suffix.
By ( "Retrieving relevant health check resources from GCE." )
gceCloud := gceController . Cloud . Provider . ( * gcecloud . GCECloud )
hcs , err := gceCloud . ListHealthChecks ( )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2018-02-01 22:18:43 +00:00
var hcToChange * compute . HealthCheck
2018-01-16 22:00:54 +00:00
for _ , hc := range hcs {
if strings . HasSuffix ( hc . Name , clusterID ) {
2018-02-01 22:18:43 +00:00
Expect ( hc . HttpHealthCheck ) . NotTo ( BeNil ( ) )
if fmt . Sprintf ( "%d" , hc . HttpHealthCheck . Port ) == nodePorts [ 0 ] {
hcToChange = hc
break
2018-01-16 22:00:54 +00:00
}
}
}
2018-02-01 22:18:43 +00:00
Expect ( hcToChange ) . NotTo ( BeNil ( ) )
2018-01-16 22:00:54 +00:00
By ( fmt . Sprintf ( "Modifying health check %v without involving ingress." , hcToChange . Name ) )
// Change timeout from 60s to 25s.
hcToChange . TimeoutSec = 25
// Change path from /healthz to /.
hcToChange . HttpHealthCheck . RequestPath = "/"
err = gceCloud . UpdateHealthCheck ( hcToChange )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
// Add one more path to ingress to trigger resource syncing.
By ( "Adding a new path to ingress and wait for it to take effect." )
jig . Update ( func ( ing * extensions . Ingress ) {
ing . Spec . Rules = append ( ing . Spec . Rules , extensions . IngressRule {
Host : "ingress.test.com" ,
IngressRuleValue : extensions . IngressRuleValue {
HTTP : & extensions . HTTPIngressRuleValue {
Paths : [ ] extensions . HTTPIngressPath {
{
Path : "/test" ,
// Copy backend from the first rule.
Backend : ing . Spec . Rules [ 0 ] . HTTP . Paths [ 0 ] . Backend ,
} ,
} ,
} ,
} ,
} )
} )
// Wait for change to take effect before checking the health check resource.
jig . WaitForIngress ( false )
// Validate the modified fields on health check are intact.
By ( "Checking if the modified health check is unchanged." )
hcAfterSync , err := gceCloud . GetHealthCheck ( hcToChange . Name )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
Expect ( hcAfterSync . HttpHealthCheck ) . ToNot ( Equal ( nil ) )
Expect ( hcAfterSync . TimeoutSec ) . To ( Equal ( hcToChange . TimeoutSec ) )
Expect ( hcAfterSync . HttpHealthCheck . RequestPath ) . To ( Equal ( hcToChange . HttpHealthCheck . RequestPath ) )
} )
2018-01-27 00:35:05 +00:00
It ( "should create ingress with pre-shared certificate" , func ( ) {
2018-03-29 02:17:44 +00:00
executePresharedCertTest ( f , jig , "" )
2018-01-27 00:35:05 +00:00
} )
2018-03-29 02:17:44 +00:00
It ( "should create ingress with backend HTTPS" , func ( ) {
executeBacksideBacksideHTTPSTest ( f , jig , "" )
2018-02-15 02:39:10 +00:00
} )
2018-04-11 21:39:43 +00:00
It ( "should support multiple TLS certs" , func ( ) {
2018-03-15 14:56:50 +00:00
By ( "Creating an ingress with no certs." )
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "multiple-certs" ) , ns , map [ string ] string {
framework . IngressStaticIPKey : ns ,
} , map [ string ] string { } )
By ( "Adding multiple certs to the ingress." )
hosts := [ ] string { "test1.ingress.com" , "test2.ingress.com" , "test3.ingress.com" , "test4.ingress.com" }
secrets := [ ] string { "tls-secret-1" , "tls-secret-2" , "tls-secret-3" , "tls-secret-4" }
certs := [ ] [ ] byte { }
for i , host := range hosts {
jig . AddHTTPS ( secrets [ i ] , host )
certs = append ( certs , jig . GetRootCA ( secrets [ i ] ) )
}
for i , host := range hosts {
err := jig . WaitForIngressWithCert ( true , [ ] string { host } , certs [ i ] )
Expect ( err ) . NotTo ( HaveOccurred ( ) , fmt . Sprintf ( "Unexpected error while waiting for ingress: %v" , err ) )
}
By ( "Remove all but one of the certs on the ingress." )
jig . RemoveHTTPS ( secrets [ 1 ] )
jig . RemoveHTTPS ( secrets [ 2 ] )
jig . RemoveHTTPS ( secrets [ 3 ] )
By ( "Test that the remaining cert is properly served." )
err := jig . WaitForIngressWithCert ( true , [ ] string { hosts [ 0 ] } , certs [ 0 ] )
Expect ( err ) . NotTo ( HaveOccurred ( ) , fmt . Sprintf ( "Unexpected error while waiting for ingress: %v" , err ) )
By ( "Add back one of the certs that was removed and check that all certs are served." )
jig . AddHTTPS ( secrets [ 1 ] , hosts [ 1 ] )
for i , host := range hosts [ : 2 ] {
err := jig . WaitForIngressWithCert ( true , [ ] string { host } , certs [ i ] )
Expect ( err ) . NotTo ( HaveOccurred ( ) , fmt . Sprintf ( "Unexpected error while waiting for ingress: %v" , err ) )
}
} )
2017-11-03 00:37:10 +00:00
It ( "multicluster ingress should get instance group annotation" , func ( ) {
name := "echomap"
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "http" ) , ns , map [ string ] string {
2018-01-27 00:35:05 +00:00
framework . IngressClassKey : framework . MulticlusterIngressClassValue ,
2017-11-03 00:37:10 +00:00
} , map [ string ] string { } )
2018-03-29 19:20:24 +00:00
By ( fmt . Sprintf ( "waiting for Ingress %s to get instance group annotation" , name ) )
2017-11-03 00:37:10 +00:00
pollErr := wait . Poll ( 2 * time . Second , framework . LoadBalancerPollTimeout , func ( ) ( bool , error ) {
ing , err := f . ClientSet . ExtensionsV1beta1 ( ) . Ingresses ( ns ) . Get ( name , metav1 . GetOptions { } )
framework . ExpectNoError ( err )
annotations := ing . Annotations
2018-03-29 19:20:24 +00:00
if annotations == nil || annotations [ framework . InstanceGroupAnnotation ] == "" {
framework . Logf ( "Waiting for ingress to get %s annotation. Found annotations: %v" , framework . InstanceGroupAnnotation , annotations )
2017-11-03 00:37:10 +00:00
return false , nil
}
return true , nil
} )
if pollErr != nil {
2018-03-29 19:20:24 +00:00
framework . ExpectNoError ( fmt . Errorf ( "Timed out waiting for ingress %s to get %s annotation" , name , framework . InstanceGroupAnnotation ) )
2017-11-03 00:37:10 +00:00
}
2018-03-29 19:20:24 +00:00
// Verify that the ingress does not get other annotations like url-map, target-proxy, backends, etc.
// Note: All resources except the firewall rule have an annotation.
umKey := framework . StatusPrefix + "/url-map"
fwKey := framework . StatusPrefix + "/forwarding-rule"
tpKey := framework . StatusPrefix + "/target-proxy"
fwsKey := framework . StatusPrefix + "/https-forwarding-rule"
tpsKey := framework . StatusPrefix + "/https-target-proxy"
scKey := framework . StatusPrefix + "/ssl-cert"
beKey := framework . StatusPrefix + "/backends"
wait . Poll ( 2 * time . Second , time . Minute , func ( ) ( bool , error ) {
ing , err := f . ClientSet . ExtensionsV1beta1 ( ) . Ingresses ( ns ) . Get ( name , metav1 . GetOptions { } )
framework . ExpectNoError ( err )
annotations := ing . Annotations
if annotations != nil && ( annotations [ umKey ] != "" || annotations [ fwKey ] != "" ||
annotations [ tpKey ] != "" || annotations [ fwsKey ] != "" || annotations [ tpsKey ] != "" ||
annotations [ scKey ] != "" || annotations [ beKey ] != "" ) {
framework . Failf ( "unexpected annotations. Expected to not have annotations for urlmap, forwarding rule, target proxy, ssl cert and backends, got: %v" , annotations )
return true , nil
}
return false , nil
} )
// Verify that the controller does not create any other resource except instance group.
// TODO(59778): Check GCE resources specific to this ingress instead of listing all resources.
if len ( gceController . ListUrlMaps ( ) ) != 0 {
framework . Failf ( "unexpected url maps, expected none, got: %v" , gceController . ListUrlMaps ( ) )
}
if len ( gceController . ListGlobalForwardingRules ( ) ) != 0 {
framework . Failf ( "unexpected forwarding rules, expected none, got: %v" , gceController . ListGlobalForwardingRules ( ) )
}
if len ( gceController . ListTargetHttpProxies ( ) ) != 0 {
framework . Failf ( "unexpected target http proxies, expected none, got: %v" , gceController . ListTargetHttpProxies ( ) )
}
if len ( gceController . ListTargetHttpsProxies ( ) ) != 0 {
framework . Failf ( "unexpected target https proxies, expected none, got: %v" , gceController . ListTargetHttpProxies ( ) )
2017-11-03 00:37:10 +00:00
}
2018-03-29 19:20:24 +00:00
if len ( gceController . ListSslCertificates ( ) ) != 0 {
framework . Failf ( "unexpected ssl certificates, expected none, got: %v" , gceController . ListSslCertificates ( ) )
}
if len ( gceController . ListGlobalBackendServices ( ) ) != 0 {
framework . Failf ( "unexpected backend service, expected none, got: %v" , gceController . ListGlobalBackendServices ( ) )
}
// Controller does not have a list command for firewall rule. We use get instead.
2018-03-31 22:40:22 +00:00
if fw , err := gceController . GetFirewallRuleOrError ( ) ; err == nil {
framework . Failf ( "unexpected nil error in getting firewall rule, expected firewall NotFound, got firewall: %v" , fw )
2018-03-29 19:20:24 +00:00
}
2017-11-03 00:37:10 +00:00
// TODO(nikhiljindal): Check the instance group annotation value and verify with a multizone cluster.
} )
2018-04-11 21:39:43 +00:00
It ( "should be able to switch between HTTPS and HTTP2 modes" , func ( ) {
2018-04-04 21:07:44 +00:00
httpsScheme := "request_scheme=https"
By ( "Create a basic HTTP2 ingress" )
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "http2" ) , ns , map [ string ] string { } , map [ string ] string { } )
jig . WaitForIngress ( true )
address , err := jig . WaitForIngressAddress ( jig . Client , jig . Ingress . Namespace , jig . Ingress . Name , framework . LoadBalancerPollTimeout )
By ( fmt . Sprintf ( "Polling on address %s and verify the backend is serving HTTP2" , address ) )
detectHttpVersionAndSchemeTest ( f , jig , address , "request_version=2" , httpsScheme )
By ( "Switch backend service to use HTTPS" )
svcList , err := f . ClientSet . CoreV1 ( ) . Services ( ns ) . List ( metav1 . ListOptions { } )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
for _ , svc := range svcList . Items {
svc . Annotations [ framework . ServiceApplicationProtocolKey ] = ` { "http2":"HTTPS"} `
_ , err = f . ClientSet . CoreV1 ( ) . Services ( ns ) . Update ( & svc )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
detectHttpVersionAndSchemeTest ( f , jig , address , "request_version=1.1" , httpsScheme )
By ( "Switch backend service to use HTTP2" )
svcList , err = f . ClientSet . CoreV1 ( ) . Services ( ns ) . List ( metav1 . ListOptions { } )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
for _ , svc := range svcList . Items {
svc . Annotations [ framework . ServiceApplicationProtocolKey ] = ` { "http2":"HTTP2"} `
_ , err = f . ClientSet . CoreV1 ( ) . Services ( ns ) . Update ( & svc )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
detectHttpVersionAndSchemeTest ( f , jig , address , "request_version=2" , httpsScheme )
} )
2016-05-31 19:12:58 +00:00
// TODO: Implement a multizone e2e that verifies traffic reaches each
// zone based on pod labels.
} )
2018-01-27 00:35:05 +00:00
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 ,
}
2018-02-06 21:51:32 +00:00
err := gceController . Init ( )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2017-10-17 23:57:07 +00:00
} )
// 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" )
2018-02-06 21:51:32 +00:00
Expect ( gceController . CleanupGCEIngressController ( ) ) . NotTo ( HaveOccurred ( ) )
2017-10-17 23:57:07 +00:00
} )
It ( "should conform to Ingress spec" , func ( ) {
jig . PollInterval = 5 * time . Second
conformanceTests = framework . CreateIngressComformanceTests ( jig , ns , map [ string ] string {
2018-06-26 17:38:12 +00:00
framework . NEGAnnotation : ` { "ingress": true} ` ,
2017-10-17 23:57:07 +00:00
} )
for _ , t := range conformanceTests {
By ( t . EntryLog )
t . Execute ( )
By ( t . ExitLog )
jig . WaitForIngress ( true )
2018-05-02 19:05:48 +00:00
usingNeg , err := gceController . BackendServiceUsingNEG ( jig . GetServicePorts ( false ) )
2017-10-17 23:57:07 +00:00
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 )
2018-05-02 19:05:48 +00:00
usingNEG , err := gceController . BackendServiceUsingNEG ( jig . GetServicePorts ( false ) )
2017-10-18 22:38:05 +00:00
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 {
2018-06-26 17:38:12 +00:00
svc . Annotations [ framework . NEGAnnotation ] = ` { "ingress": false} `
2017-10-18 22:38:05 +00:00
_ , err = f . ClientSet . CoreV1 ( ) . Services ( ns ) . Update ( & svc )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
wait . Poll ( 5 * time . Second , framework . LoadBalancerPollTimeout , func ( ) ( bool , error ) {
2018-05-02 19:05:48 +00:00
return gceController . BackendServiceUsingIG ( jig . GetServicePorts ( true ) )
2017-10-18 22:38:05 +00:00
} )
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 {
2018-06-26 17:38:12 +00:00
svc . Annotations [ framework . NEGAnnotation ] = ` { "ingress": true} `
2017-10-18 22:38:05 +00:00
_ , err = f . ClientSet . CoreV1 ( ) . Services ( ns ) . Update ( & svc )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
wait . Poll ( 5 * time . Second , framework . LoadBalancerPollTimeout , func ( ) ( bool , error ) {
2018-05-02 19:05:48 +00:00
return gceController . BackendServiceUsingNEG ( jig . GetServicePorts ( false ) )
2017-10-18 22:38:05 +00:00
} )
jig . WaitForIngress ( true )
} )
2017-10-18 23:44:48 +00:00
2018-06-29 21:44:08 +00:00
It ( "should be able to create a ClusterIP service" , func ( ) {
2018-05-16 16:30:40 +00:00
var err error
By ( "Create a basic HTTP ingress using NEG" )
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "neg-clusterip" ) , ns , map [ string ] string { } , map [ string ] string { } )
jig . WaitForIngress ( true )
svcPorts := jig . GetServicePorts ( false )
usingNEG , err := gceController . BackendServiceUsingNEG ( svcPorts )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
Expect ( usingNEG ) . To ( BeTrue ( ) )
// ClusterIP ServicePorts have no NodePort
for _ , sp := range svcPorts {
Expect ( sp . NodePort ) . To ( Equal ( int32 ( 0 ) ) )
}
} )
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 ( ) )
}
2018-03-29 19:20:24 +00:00
wait . Poll ( 10 * time . Second , framework . NEGUpdateTimeout , func ( ) ( bool , error ) {
2017-10-18 23:44:48 +00:00
res , err := jig . GetDistinctResponseFromIngress ( )
if err != nil {
2018-01-24 22:12:28 +00:00
return false , nil
2017-10-18 23:44:48 +00:00
}
2018-01-24 22:12:28 +00:00
return res . Len ( ) == num , nil
2017-10-18 23:44:48 +00:00
} )
}
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 )
2018-05-02 19:05:48 +00:00
usingNEG , err := gceController . BackendServiceUsingNEG ( jig . GetServicePorts ( false ) )
2017-10-18 23:44:48 +00:00
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-23 19:23:55 +00:00
It ( "rolling update backend pods should not cause service disruption" , func ( ) {
name := "hostname"
replicas := 8
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 )
2018-05-02 19:05:48 +00:00
usingNEG , err := gceController . BackendServiceUsingNEG ( jig . GetServicePorts ( false ) )
2017-10-23 19:23:55 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
Expect ( usingNEG ) . To ( BeTrue ( ) )
By ( fmt . Sprintf ( "Scale backend replicas to %d" , replicas ) )
scale , err := f . ClientSet . ExtensionsV1beta1 ( ) . Deployments ( ns ) . GetScale ( name , metav1 . GetOptions { } )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
scale . Spec . Replicas = int32 ( replicas )
_ , err = f . ClientSet . ExtensionsV1beta1 ( ) . Deployments ( ns ) . UpdateScale ( name , scale )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2018-01-24 22:12:28 +00:00
wait . Poll ( 10 * time . Second , framework . LoadBalancerPollTimeout , func ( ) ( bool , error ) {
2017-10-23 19:23:55 +00:00
res , err := jig . GetDistinctResponseFromIngress ( )
if err != nil {
2018-01-24 22:12:28 +00:00
return false , nil
2017-10-23 19:23:55 +00:00
}
2018-01-24 22:12:28 +00:00
return res . Len ( ) == replicas , nil
2017-10-23 19:23:55 +00:00
} )
By ( "Trigger rolling update and observe service disruption" )
deploy , err := f . ClientSet . ExtensionsV1beta1 ( ) . Deployments ( ns ) . Get ( name , metav1 . GetOptions { } )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
// trigger by changing graceful termination period to 60 seconds
gracePeriod := int64 ( 60 )
deploy . Spec . Template . Spec . TerminationGracePeriodSeconds = & gracePeriod
_ , err = f . ClientSet . ExtensionsV1beta1 ( ) . Deployments ( ns ) . Update ( deploy )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2018-01-24 22:12:28 +00:00
wait . Poll ( 10 * time . Second , framework . LoadBalancerPollTimeout , func ( ) ( bool , error ) {
2017-10-23 19:23:55 +00:00
res , err := jig . GetDistinctResponseFromIngress ( )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
deploy , err := f . ClientSet . ExtensionsV1beta1 ( ) . Deployments ( ns ) . Get ( name , metav1 . GetOptions { } )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if int ( deploy . Status . UpdatedReplicas ) == replicas {
if res . Len ( ) == replicas {
return true , nil
} else {
framework . Logf ( "Expecting %d different responses, but got %d." , replicas , res . Len ( ) )
return false , nil
}
} else {
framework . Logf ( "Waiting for rolling update to finished. Keep sending traffic." )
return false , nil
}
} )
} )
2018-06-21 00:12:32 +00:00
2018-06-29 21:44:08 +00:00
It ( "should sync endpoints for both Ingress-referenced NEG and standalone NEG" , func ( ) {
2018-06-21 00:12:32 +00:00
name := "hostname"
2018-06-22 23:14:51 +00:00
expectedKeys := [ ] int32 { 80 , 443 }
2018-06-21 00:12:32 +00:00
scaleAndValidateExposedNEG := 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 ( 10 * time . Second , framework . NEGUpdateTimeout , func ( ) ( bool , error ) {
svc , err := f . ClientSet . CoreV1 ( ) . Services ( ns ) . Get ( name , metav1 . GetOptions { } )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
var status framework . NegStatus
v , ok := svc . Annotations [ framework . NEGStatusAnnotation ]
if ! ok {
2018-06-22 23:14:51 +00:00
// Wait for NEG sync loop to find NEGs
framework . Logf ( "Waiting for %v, got: %+v" , framework . NEGStatusAnnotation , svc . Annotations )
2018-06-21 00:12:32 +00:00
return false , nil
}
err = json . Unmarshal ( [ ] byte ( v ) , & status )
if err != nil {
framework . Logf ( "Error in parsing Expose NEG annotation: %v" , err )
return false , nil
}
framework . Logf ( "Got %v: %v" , framework . NEGStatusAnnotation , v )
2018-06-22 23:14:51 +00:00
// Expect 2 NEGs to be created based on the test setup (neg-exposed)
if len ( status . NetworkEndpointGroups ) != 2 {
2018-06-23 00:21:28 +00:00
framework . Logf ( "Expected 2 NEGs, got %d" , len ( status . NetworkEndpointGroups ) )
2018-06-21 00:12:32 +00:00
return false , nil
}
2018-06-22 23:14:51 +00:00
for _ , port := range expectedKeys {
if _ , ok := status . NetworkEndpointGroups [ port ] ; ! ok {
framework . Logf ( "Expected ServicePort key %v, but does not exist" , port )
}
}
2018-06-23 00:21:28 +00:00
if len ( status . NetworkEndpointGroups ) != len ( expectedKeys ) {
framework . Logf ( "Expected length of %+v to equal length of %+v, but does not" , status . NetworkEndpointGroups , expectedKeys )
2018-06-21 00:12:32 +00:00
}
gceCloud := gceController . Cloud . Provider . ( * gcecloud . GCECloud )
2018-06-23 00:21:28 +00:00
for _ , neg := range status . NetworkEndpointGroups {
2018-06-22 23:14:51 +00:00
networkEndpoints , err := gceCloud . ListNetworkEndpoints ( neg , gceController . Cloud . Zone , false )
2018-06-21 00:12:32 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2018-06-22 23:14:51 +00:00
if len ( networkEndpoints ) != num {
framework . Logf ( "Expect number of endpoints to be %d, but got %d" , num , len ( networkEndpoints ) )
2018-06-21 00:12:32 +00:00
return false , nil
}
}
2018-06-22 23:14:51 +00:00
return true , nil
2018-06-21 00:12:32 +00:00
} )
}
By ( "Create a basic HTTP ingress using NEG" )
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "neg-exposed" ) , ns , map [ string ] string { } , map [ string ] string { } )
jig . WaitForIngress ( true )
usingNEG , err := gceController . BackendServiceUsingNEG ( jig . GetServicePorts ( false ) )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
Expect ( usingNEG ) . To ( BeTrue ( ) )
// initial replicas number is 1
scaleAndValidateExposedNEG ( 1 )
By ( "Scale up number of backends to 5" )
scaleAndValidateExposedNEG ( 5 )
By ( "Scale down number of backends to 3" )
scaleAndValidateExposedNEG ( 3 )
By ( "Scale up number of backends to 6" )
scaleAndValidateExposedNEG ( 6 )
By ( "Scale down number of backends to 2" )
scaleAndValidateExposedNEG ( 3 )
} )
2017-10-17 23:57:07 +00:00
} )
2016-08-22 22:15:12 +00:00
2018-02-02 02:14:57 +00:00
Describe ( "GCE [Slow] [Feature:kubemci]" , func ( ) {
2018-03-20 02:47:42 +00:00
var gceController * framework . GCEIngressController
2018-04-03 06:44:53 +00:00
var ipName , ipAddress string
2018-03-20 02:47:42 +00:00
2018-02-02 02:14:57 +00:00
// Platform specific setup
BeforeEach ( func ( ) {
framework . SkipUnlessProviderIs ( "gce" , "gke" )
jig . Class = framework . MulticlusterIngressClassValue
2018-03-29 02:17:44 +00:00
jig . PollInterval = 5 * time . Second
2018-03-20 02:47:42 +00:00
By ( "Initializing gce controller" )
gceController = & framework . GCEIngressController {
Ns : ns ,
Client : jig . Client ,
Cloud : framework . TestContext . CloudConfig ,
}
err := gceController . Init ( )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2018-03-29 02:17:44 +00:00
// TODO(https://github.com/GoogleCloudPlatform/k8s-multicluster-ingress/issues/19):
// Kubemci should reserve a static ip if user has not specified one.
ipName = "kubemci-" + string ( uuid . NewUUID ( ) )
// ip released when the rest of lb resources are deleted in CleanupGCEIngressController
2018-04-03 06:44:53 +00:00
ipAddress = gceController . CreateStaticIP ( ipName )
2018-03-29 02:17:44 +00:00
By ( fmt . Sprintf ( "allocated static ip %v: %v through the GCE cloud provider" , ipName , ipAddress ) )
2018-02-02 02:14:57 +00:00
} )
// Platform specific cleanup
AfterEach ( func ( ) {
if CurrentGinkgoTestDescription ( ) . Failed {
framework . DescribeIng ( ns )
}
if jig . Ingress == nil {
By ( "No ingress created, no cleanup necessary" )
2018-04-04 19:48:39 +00:00
} else {
By ( "Deleting ingress" )
jig . TryDeleteIngress ( )
2018-02-02 02:14:57 +00:00
}
2018-03-20 02:47:42 +00:00
By ( "Cleaning up cloud resources" )
Expect ( gceController . CleanupGCEIngressController ( ) ) . NotTo ( HaveOccurred ( ) )
2018-02-02 02:14:57 +00:00
} )
It ( "should conform to Ingress spec" , func ( ) {
2018-03-20 02:47:42 +00:00
conformanceTests = framework . CreateIngressComformanceTests ( jig , ns , map [ string ] string {
framework . IngressStaticIPKey : ipName ,
} )
2018-02-02 02:14:57 +00:00
for _ , t := range conformanceTests {
By ( t . EntryLog )
t . Execute ( )
By ( t . ExitLog )
2018-03-20 02:47:42 +00:00
jig . WaitForIngress ( false /*waitForNodePort*/ )
2018-02-02 02:14:57 +00:00
}
} )
2018-03-29 02:17:44 +00:00
It ( "should create ingress with pre-shared certificate" , func ( ) {
executePresharedCertTest ( f , jig , ipName )
} )
It ( "should create ingress with backend HTTPS" , func ( ) {
executeBacksideBacksideHTTPSTest ( f , jig , ipName )
} )
2018-04-03 06:44:53 +00:00
It ( "should support https-only annotation" , func ( ) {
executeStaticIPHttpsOnlyTest ( f , jig , ipName , ipAddress )
} )
2018-04-03 06:14:17 +00:00
It ( "should remove clusters as expected" , func ( ) {
ingAnnotations := map [ string ] string {
framework . IngressStaticIPKey : ipName ,
}
ingFilePath := filepath . Join ( framework . IngressManifestPath , "http" )
jig . CreateIngress ( ingFilePath , ns , ingAnnotations , map [ string ] string { } )
jig . WaitForIngress ( false /*waitForNodePort*/ )
name := jig . Ingress . Name
// Verify that the ingress is spread to 1 cluster as expected.
verifyKubemciStatusHas ( name , "is spread across 1 cluster" )
2018-04-05 18:33:56 +00:00
// Validate that removing the ingress from all clusters throws an error.
2018-04-03 06:14:17 +00:00
// Reuse the ingress file created while creating the ingress.
filePath := filepath . Join ( framework . TestContext . OutputDir , "mci.yaml" )
2018-04-09 17:15:38 +00:00
output , err := framework . RunKubemciWithKubeconfig ( "remove-clusters" , name , "--ingress=" + filePath )
if err != nil {
framework . Failf ( "unexpected error in running kubemci remove-clusters command to remove from all clusters: %s" , err )
2018-04-05 18:33:56 +00:00
}
2018-04-09 17:15:38 +00:00
if ! strings . Contains ( output , "You should use kubemci delete to delete the ingress completely" ) {
framework . Failf ( "unexpected output in removing an ingress from all clusters, expected the output to include: You should use kubemci delete to delete the ingress completely, actual output: %s" , output )
}
// Verify that the ingress is still spread to 1 cluster as expected.
verifyKubemciStatusHas ( name , "is spread across 1 cluster" )
2018-04-05 18:33:56 +00:00
// remove-clusters should succeed with --force=true
if _ , err := framework . RunKubemciWithKubeconfig ( "remove-clusters" , name , "--ingress=" + filePath , "--force=true" ) ; err != nil {
framework . Failf ( "unexpected error in running kubemci remove-clusters to remove from all clusters with --force=true: %s" , err )
2018-04-03 06:14:17 +00:00
}
verifyKubemciStatusHas ( name , "is spread across 0 cluster" )
} )
2018-04-04 19:15:13 +00:00
It ( "single and multi-cluster ingresses should be able to exist together" , func ( ) {
By ( "Creating a single cluster ingress first" )
jig . Class = ""
singleIngFilePath := filepath . Join ( framework . IngressManifestPath , "static-ip-2" )
jig . CreateIngress ( singleIngFilePath , ns , map [ string ] string { } , map [ string ] string { } )
jig . WaitForIngress ( false /*waitForNodePort*/ )
// jig.Ingress will be overwritten when we create MCI, so keep a reference.
singleIng := jig . Ingress
// Create the multi-cluster ingress next.
By ( "Creating a multi-cluster ingress next" )
jig . Class = framework . MulticlusterIngressClassValue
ingAnnotations := map [ string ] string {
framework . IngressStaticIPKey : ipName ,
}
multiIngFilePath := filepath . Join ( framework . IngressManifestPath , "http" )
jig . CreateIngress ( multiIngFilePath , ns , ingAnnotations , map [ string ] string { } )
jig . WaitForIngress ( false /*waitForNodePort*/ )
mciIngress := jig . Ingress
By ( "Deleting the single cluster ingress and verifying that multi-cluster ingress continues to work" )
jig . Ingress = singleIng
jig . Class = ""
jig . TryDeleteIngress ( )
jig . Ingress = mciIngress
jig . Class = framework . MulticlusterIngressClassValue
jig . WaitForIngress ( false /*waitForNodePort*/ )
By ( "Cleanup: Deleting the multi-cluster ingress" )
jig . TryDeleteIngress ( )
} )
2018-02-02 02:14:57 +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
} )
2018-03-29 02:17:44 +00:00
2018-04-03 06:14:17 +00:00
// verifyKubemciStatusHas fails if kubemci get-status output for the given mci does not have the given expectedSubStr.
func verifyKubemciStatusHas ( name , expectedSubStr string ) {
statusStr , err := framework . RunKubemciCmd ( "get-status" , name )
if err != nil {
framework . Failf ( "unexpected error in running kubemci get-status %s: %s" , name , err )
}
if ! strings . Contains ( statusStr , expectedSubStr ) {
framework . Failf ( "expected status to have sub string %s, actual status: %s" , expectedSubStr , statusStr )
}
}
2018-03-29 02:17:44 +00:00
func executePresharedCertTest ( f * framework . Framework , jig * framework . IngressTestJig , staticIPName string ) {
preSharedCertName := "test-pre-shared-cert"
By ( fmt . Sprintf ( "Creating ssl certificate %q on GCE" , preSharedCertName ) )
testHostname := "test.ingress.com"
cert , key , err := framework . GenerateRSACerts ( testHostname , true )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
gceCloud , err := framework . GetGCECloud ( )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
defer func ( ) {
// We would not be able to delete the cert until ingress controller
// cleans up the target proxy that references it.
By ( "Deleting ingress before deleting ssl certificate" )
if jig . Ingress != nil {
jig . TryDeleteIngress ( )
}
By ( fmt . Sprintf ( "Deleting ssl certificate %q on GCE" , preSharedCertName ) )
err := wait . Poll ( framework . LoadBalancerPollInterval , framework . LoadBalancerCleanupTimeout , func ( ) ( bool , error ) {
if err := gceCloud . DeleteSslCertificate ( preSharedCertName ) ; err != nil && ! errors . IsNotFound ( err ) {
framework . Logf ( "Failed to delete ssl certificate %q: %v. Retrying..." , preSharedCertName , err )
return false , nil
}
return true , nil
} )
Expect ( err ) . NotTo ( HaveOccurred ( ) , fmt . Sprintf ( "Failed to delete ssl certificate %q: %v" , preSharedCertName , err ) )
} ( )
_ , err = gceCloud . CreateSslCertificate ( & compute . SslCertificate {
Name : preSharedCertName ,
Certificate : string ( cert ) ,
PrivateKey : string ( key ) ,
Description : "pre-shared cert for ingress testing" ,
} )
Expect ( err ) . NotTo ( HaveOccurred ( ) , fmt . Sprintf ( "Failed to create ssl certificate %q: %v" , preSharedCertName , err ) )
By ( "Creating an ingress referencing the pre-shared certificate" )
// Create an ingress referencing this cert using pre-shared-cert annotation.
ingAnnotations := map [ string ] string {
framework . IngressPreSharedCertKey : preSharedCertName ,
// Disallow HTTP to save resources. This is irrelevant to the
// pre-shared cert test.
framework . IngressAllowHTTPKey : "false" ,
}
if staticIPName != "" {
ingAnnotations [ framework . IngressStaticIPKey ] = staticIPName
}
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "pre-shared-cert" ) , f . Namespace . Name , ingAnnotations , map [ string ] string { } )
By ( "Test that ingress works with the pre-shared certificate" )
err = jig . WaitForIngressWithCert ( true , [ ] string { testHostname } , cert )
Expect ( err ) . NotTo ( HaveOccurred ( ) , fmt . Sprintf ( "Unexpected error while waiting for ingress: %v" , err ) )
}
2018-04-03 06:44:53 +00:00
func executeStaticIPHttpsOnlyTest ( f * framework . Framework , jig * framework . IngressTestJig , ipName , ip string ) {
jig . CreateIngress ( filepath . Join ( framework . IngressManifestPath , "static-ip" ) , f . Namespace . Name , map [ string ] string {
framework . IngressStaticIPKey : ipName ,
framework . IngressAllowHTTPKey : "false" ,
} , map [ string ] string { } )
By ( "waiting for Ingress to come up with ip: " + ip )
httpClient := framework . BuildInsecureClient ( framework . IngressReqTimeout )
framework . ExpectNoError ( framework . PollURL ( fmt . Sprintf ( "https://%s/" , ip ) , "" , framework . LoadBalancerPollTimeout , jig . PollInterval , httpClient , false ) )
By ( "should reject HTTP traffic" )
framework . ExpectNoError ( framework . PollURL ( fmt . Sprintf ( "http://%s/" , ip ) , "" , framework . LoadBalancerPollTimeout , jig . PollInterval , httpClient , true ) )
}
2018-03-29 02:17:44 +00:00
func executeBacksideBacksideHTTPSTest ( f * framework . Framework , jig * framework . IngressTestJig , staticIPName string ) {
By ( "Creating a set of ingress, service and deployment that have backside re-encryption configured" )
deployCreated , svcCreated , ingCreated , err := jig . SetUpBacksideHTTPSIngress ( f . ClientSet , f . Namespace . Name , staticIPName )
defer func ( ) {
By ( "Cleaning up re-encryption ingress, service and deployment" )
if errs := jig . DeleteTestResource ( f . ClientSet , deployCreated , svcCreated , ingCreated ) ; len ( errs ) > 0 {
framework . Failf ( "Failed to cleanup re-encryption ingress: %v" , errs )
}
} ( )
Expect ( err ) . NotTo ( HaveOccurred ( ) , "Failed to create re-encryption ingress" )
By ( fmt . Sprintf ( "Waiting for ingress %s to come up" , ingCreated . Name ) )
ingIP , err := jig . WaitForIngressAddress ( f . ClientSet , f . Namespace . Name , ingCreated . Name , framework . LoadBalancerPollTimeout )
Expect ( err ) . NotTo ( HaveOccurred ( ) , "Failed to wait for ingress IP" )
By ( fmt . Sprintf ( "Polling on address %s and verify the backend is serving HTTPS" , ingIP ) )
timeoutClient := & http . Client { Timeout : framework . IngressReqTimeout }
err = wait . PollImmediate ( framework . LoadBalancerPollInterval , framework . LoadBalancerPollTimeout , func ( ) ( bool , error ) {
resp , err := framework . SimpleGET ( timeoutClient , fmt . Sprintf ( "http://%s" , ingIP ) , "" )
if err != nil {
framework . Logf ( "SimpleGET failed: %v" , err )
return false , nil
}
if ! strings . Contains ( resp , "request_scheme=https" ) {
return false , fmt . Errorf ( "request wasn't served by HTTPS, response body: %s" , resp )
}
framework . Logf ( "Poll succeeded, request was served by HTTPS" )
return true , nil
} )
Expect ( err ) . NotTo ( HaveOccurred ( ) , "Failed to verify backside re-encryption ingress" )
}
2018-04-04 21:07:44 +00:00
func detectHttpVersionAndSchemeTest ( f * framework . Framework , jig * framework . IngressTestJig , address , version , scheme string ) {
timeoutClient := & http . Client { Timeout : framework . IngressReqTimeout }
resp := ""
err := wait . PollImmediate ( framework . LoadBalancerPollInterval , framework . LoadBalancerPollTimeout , func ( ) ( bool , error ) {
resp , err := framework . SimpleGET ( timeoutClient , fmt . Sprintf ( "http://%s" , address ) , "" )
if err != nil {
framework . Logf ( "SimpleGET failed: %v" , err )
return false , nil
}
if ! strings . Contains ( resp , version ) {
framework . Logf ( "Waiting for transition to HTTP/2" )
return false , nil
}
if ! strings . Contains ( resp , scheme ) {
return false , nil
}
framework . Logf ( "Poll succeeded, request was served by HTTP2" )
return true , nil
} )
Expect ( err ) . NotTo ( HaveOccurred ( ) , fmt . Sprintf ( "Failed to get %s or %s, response body: %s" , version , scheme , resp ) )
}