2015-01-13 02:11:27 +00:00
/ *
2016-08-17 04:07:17 +00:00
Copyright 2016 The Kubernetes Authors .
2015-01-13 02:11:27 +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 .
* /
package e2e
import (
2016-08-22 17:48:00 +00:00
"bytes"
2015-01-13 02:11:27 +00:00
"fmt"
2015-03-21 00:35:43 +00:00
"io/ioutil"
2015-05-22 23:01:35 +00:00
"math/rand"
2015-09-28 20:57:58 +00:00
"net"
2015-03-21 00:35:43 +00:00
"net/http"
2015-02-18 19:30:18 +00:00
"sort"
2015-08-04 13:24:37 +00:00
"strconv"
2015-03-21 00:35:43 +00:00
"strings"
2015-01-13 02:11:27 +00:00
"time"
2015-08-05 22:05:17 +00:00
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api/errors"
2016-11-18 20:55:17 +00:00
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/api/v1/service"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
2016-05-06 20:15:49 +00:00
"k8s.io/kubernetes/pkg/controller/endpoint"
2016-01-30 04:35:32 +00:00
"k8s.io/kubernetes/pkg/labels"
2015-06-26 08:08:48 +00:00
"k8s.io/kubernetes/pkg/types"
2015-11-10 06:28:45 +00:00
"k8s.io/kubernetes/pkg/util/intstr"
2016-01-06 15:56:41 +00:00
utilnet "k8s.io/kubernetes/pkg/util/net"
2015-12-14 20:26:23 +00:00
"k8s.io/kubernetes/pkg/util/sets"
2016-07-26 15:13:18 +00:00
"k8s.io/kubernetes/pkg/util/uuid"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/util/wait"
2016-04-07 17:21:31 +00:00
"k8s.io/kubernetes/test/e2e/framework"
2016-10-12 11:37:37 +00:00
testutils "k8s.io/kubernetes/test/utils"
2015-01-13 02:11:27 +00:00
)
2016-07-26 12:28:12 +00:00
const (
// Maximum time a kube-proxy daemon on a node is allowed to not
// notice a Service update, such as type=NodePort.
// TODO: This timeout should be O(10s), observed values are O(1m), 5m is very
// liberal. Fix tracked in #20567.
kubeProxyLagTimeout = 5 * time . Minute
2016-01-27 21:42:00 +00:00
2016-07-26 12:28:12 +00:00
// Maximum time a load balancer is allowed to not respond after creation.
loadBalancerLagTimeoutDefault = 2 * time . Minute
2016-02-10 14:31:52 +00:00
2016-07-26 12:28:12 +00:00
// On AWS there is a delay between ELB creation and serving traffic;
// a few minutes is typical, so use 10m.
loadBalancerLagTimeoutAWS = 10 * time . Minute
2016-01-30 04:35:32 +00:00
2016-07-26 12:28:12 +00:00
// How long to wait for a load balancer to be created/modified.
//TODO: once support ticket 21807001 is resolved, reduce this timeout back to something reasonable
2016-08-02 10:30:14 +00:00
loadBalancerCreateTimeoutDefault = 20 * time . Minute
2016-11-08 14:08:14 +00:00
loadBalancerCreateTimeoutLarge = 2 * time . Hour
2016-10-03 18:53:28 +00:00
largeClusterMinNodesNumber = 100
// Don't test with more than 3 nodes.
// Many tests create an endpoint per node, in large clusters, this is
// resource and time intensive.
maxNodesForEndpointsTests = 3
2016-10-26 10:01:57 +00:00
// timeout is used for most polling/waiting activities
timeout = 60 * time . Second
2016-07-26 12:28:12 +00:00
)
2016-01-30 04:35:32 +00:00
2015-05-22 23:01:35 +00:00
// This should match whatever the default/configured range is
2016-01-06 15:56:41 +00:00
var ServiceNodePortRange = utilnet . PortRange { Base : 30000 , Size : 2768 }
2015-05-22 23:01:35 +00:00
2016-04-07 17:21:31 +00:00
var _ = framework . KubeDescribe ( "Services" , func ( ) {
f := framework . NewDefaultFramework ( "services" )
2015-05-28 02:32:27 +00:00
2016-10-19 13:55:39 +00:00
var cs clientset . Interface
2016-11-18 20:55:17 +00:00
var internalClientset internalclientset . Interface
2016-09-07 02:48:04 +00:00
serviceLBNames := [ ] string { }
2015-02-05 13:50:07 +00:00
BeforeEach ( func ( ) {
2016-10-19 13:55:39 +00:00
cs = f . ClientSet
2016-11-18 20:55:17 +00:00
internalClientset = f . InternalClientset
2015-05-08 17:07:32 +00:00
} )
2016-09-07 02:48:04 +00:00
AfterEach ( func ( ) {
if CurrentGinkgoTestDescription ( ) . Failed {
describeSvc ( f . Namespace . Name )
}
for _ , lb := range serviceLBNames {
framework . Logf ( "cleaning gce resource for %s" , lb )
cleanupServiceGCEResources ( lb )
}
//reset serviceLBNames
serviceLBNames = [ ] string { }
} )
2015-05-14 01:50:28 +00:00
// TODO: We get coverage of TCP/UDP and multi-port services through the DNS test. We should have a simpler test for multi-port TCP here.
2015-09-29 21:30:45 +00:00
2015-10-07 14:09:24 +00:00
It ( "should provide secure master service [Conformance]" , func ( ) {
2016-11-18 20:55:17 +00:00
_ , err := cs . Core ( ) . Services ( v1 . NamespaceDefault ) . Get ( "kubernetes" )
2015-05-13 23:13:19 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2015-02-05 14:05:45 +00:00
} )
2015-02-09 20:37:56 +00:00
2015-10-07 14:09:24 +00:00
It ( "should serve a basic endpoint from pods [Conformance]" , func ( ) {
2016-01-30 04:35:32 +00:00
// TODO: use the ServiceTestJig here
2015-02-18 19:30:18 +00:00
serviceName := "endpoint-test2"
2015-09-29 21:30:45 +00:00
ns := f . Namespace . Name
2015-02-09 20:37:56 +00:00
labels := map [ string ] string {
"foo" : "bar" ,
"baz" : "blah" ,
}
2015-09-29 21:30:45 +00:00
By ( "creating service " + serviceName + " in namespace " + ns )
2015-02-09 20:37:56 +00:00
defer func ( ) {
2016-10-18 13:00:38 +00:00
err := cs . Core ( ) . Services ( ns ) . Delete ( serviceName , nil )
2015-02-09 20:37:56 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
} ( )
2016-11-18 20:55:17 +00:00
service := & v1 . Service {
ObjectMeta : v1 . ObjectMeta {
2015-02-09 20:37:56 +00:00
Name : serviceName ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . ServiceSpec {
2015-03-13 15:16:41 +00:00
Selector : labels ,
2016-11-18 20:55:17 +00:00
Ports : [ ] v1 . ServicePort { {
2015-03-13 15:16:41 +00:00
Port : 80 ,
2015-11-10 06:28:45 +00:00
TargetPort : intstr . FromInt ( 80 ) ,
2015-03-13 15:16:41 +00:00
} } ,
2015-02-09 20:37:56 +00:00
} ,
}
2016-10-18 13:00:38 +00:00
_ , err := cs . Core ( ) . Services ( ns ) . Create ( service )
2015-02-09 20:37:56 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { } )
2015-02-09 20:37:56 +00:00
2015-09-29 21:30:45 +00:00
names := map [ string ] bool { }
2015-02-09 20:37:56 +00:00
defer func ( ) {
2015-09-29 21:30:45 +00:00
for name := range names {
2016-10-18 13:00:38 +00:00
err := cs . Core ( ) . Pods ( ns ) . Delete ( name , nil )
2015-02-09 20:37:56 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
} ( )
2015-09-29 21:30:45 +00:00
name1 := "pod1"
name2 := "pod2"
2015-02-23 22:57:08 +00:00
2016-11-18 20:55:17 +00:00
createPodOrFail ( cs , ns , name1 , labels , [ ] v1 . ContainerPort { { ContainerPort : 80 } } )
2015-09-29 21:30:45 +00:00
names [ name1 ] = true
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { name1 : { 80 } } )
2015-02-09 20:37:56 +00:00
2016-11-18 20:55:17 +00:00
createPodOrFail ( cs , ns , name2 , labels , [ ] v1 . ContainerPort { { ContainerPort : 80 } } )
2015-09-29 21:30:45 +00:00
names [ name2 ] = true
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { name1 : { 80 } , name2 : { 80 } } )
2015-02-09 20:37:56 +00:00
2016-10-18 13:00:38 +00:00
deletePodOrFail ( cs , ns , name1 )
2015-09-29 21:30:45 +00:00
delete ( names , name1 )
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { name2 : { 80 } } )
2015-02-09 20:37:56 +00:00
2016-10-18 13:00:38 +00:00
deletePodOrFail ( cs , ns , name2 )
2015-09-29 21:30:45 +00:00
delete ( names , name2 )
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { } )
2015-06-16 01:40:11 +00:00
} )
2015-05-08 17:07:32 +00:00
2015-10-07 14:09:24 +00:00
It ( "should serve multiport endpoints from pods [Conformance]" , func ( ) {
2016-01-30 04:35:32 +00:00
// TODO: use the ServiceTestJig here
2015-05-08 17:07:32 +00:00
// repacking functionality is intentionally not tested here - it's better to test it in an integration test.
serviceName := "multi-endpoint-test"
2015-09-29 21:30:45 +00:00
ns := f . Namespace . Name
2015-05-08 17:07:32 +00:00
defer func ( ) {
2016-10-18 13:00:38 +00:00
err := cs . Core ( ) . Services ( ns ) . Delete ( serviceName , nil )
2015-05-08 17:07:32 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
} ( )
labels := map [ string ] string { "foo" : "bar" }
svc1port := "svc1"
svc2port := "svc2"
2015-09-29 21:30:45 +00:00
By ( "creating service " + serviceName + " in namespace " + ns )
2016-11-18 20:55:17 +00:00
service := & v1 . Service {
ObjectMeta : v1 . ObjectMeta {
2015-05-08 17:07:32 +00:00
Name : serviceName ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . ServiceSpec {
2015-05-08 17:07:32 +00:00
Selector : labels ,
2016-11-18 20:55:17 +00:00
Ports : [ ] v1 . ServicePort {
2015-05-08 17:07:32 +00:00
{
Name : "portname1" ,
Port : 80 ,
2015-11-10 06:28:45 +00:00
TargetPort : intstr . FromString ( svc1port ) ,
2015-05-08 17:07:32 +00:00
} ,
{
Name : "portname2" ,
Port : 81 ,
2015-11-10 06:28:45 +00:00
TargetPort : intstr . FromString ( svc2port ) ,
2015-05-08 17:07:32 +00:00
} ,
} ,
} ,
}
2016-10-18 13:00:38 +00:00
_ , err := cs . Core ( ) . Services ( ns ) . Create ( service )
2015-05-08 17:07:32 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
port1 := 100
port2 := 101
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { } )
2015-05-08 17:07:32 +00:00
2015-09-29 21:30:45 +00:00
names := map [ string ] bool { }
2015-05-08 17:07:32 +00:00
defer func ( ) {
2015-09-29 21:30:45 +00:00
for name := range names {
2016-10-18 13:00:38 +00:00
err := cs . Core ( ) . Pods ( ns ) . Delete ( name , nil )
2015-05-08 17:07:32 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
} ( )
2016-11-18 20:55:17 +00:00
containerPorts1 := [ ] v1 . ContainerPort {
2015-05-08 17:07:32 +00:00
{
Name : svc1port ,
2016-04-27 04:35:14 +00:00
ContainerPort : int32 ( port1 ) ,
2015-05-08 17:07:32 +00:00
} ,
}
2016-11-18 20:55:17 +00:00
containerPorts2 := [ ] v1 . ContainerPort {
2015-05-08 17:07:32 +00:00
{
Name : svc2port ,
2016-04-27 04:35:14 +00:00
ContainerPort : int32 ( port2 ) ,
2015-05-08 17:07:32 +00:00
} ,
}
2015-09-29 21:30:45 +00:00
podname1 := "pod1"
podname2 := "pod2"
2016-10-18 13:00:38 +00:00
createPodOrFail ( cs , ns , podname1 , labels , containerPorts1 )
2015-09-29 21:30:45 +00:00
names [ podname1 ] = true
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { podname1 : { port1 } } )
2015-05-08 17:07:32 +00:00
2016-10-18 13:00:38 +00:00
createPodOrFail ( cs , ns , podname2 , labels , containerPorts2 )
2015-09-29 21:30:45 +00:00
names [ podname2 ] = true
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { podname1 : { port1 } , podname2 : { port2 } } )
2015-05-08 17:07:32 +00:00
2016-10-18 13:00:38 +00:00
deletePodOrFail ( cs , ns , podname1 )
2015-09-29 21:30:45 +00:00
delete ( names , podname1 )
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { podname2 : { port2 } } )
2015-05-08 17:07:32 +00:00
2016-10-18 13:00:38 +00:00
deletePodOrFail ( cs , ns , podname2 )
2015-09-29 21:30:45 +00:00
delete ( names , podname2 )
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { } )
2015-06-16 01:40:11 +00:00
} )
2015-03-20 21:04:41 +00:00
2016-08-17 04:07:17 +00:00
It ( "should preserve source pod IP for traffic thru service cluster IP" , func ( ) {
serviceName := "sourceip-test"
ns := f . Namespace . Name
By ( "creating a TCP service " + serviceName + " with type=ClusterIP in namespace " + ns )
2016-10-18 13:00:38 +00:00
jig := NewServiceTestJig ( cs , serviceName )
2016-08-17 04:07:17 +00:00
servicePort := 8080
tcpService := jig . CreateTCPServiceWithPort ( ns , nil , int32 ( servicePort ) )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( tcpService , v1 . ServiceTypeClusterIP )
2016-08-17 04:07:17 +00:00
defer func ( ) {
framework . Logf ( "Cleaning up the sourceip test service" )
2016-10-18 13:00:38 +00:00
err := cs . Core ( ) . Services ( ns ) . Delete ( serviceName , nil )
2016-08-17 04:07:17 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
} ( )
serviceIp := tcpService . Spec . ClusterIP
framework . Logf ( "sourceip-test cluster ip: %s" , serviceIp )
By ( "Picking multiple nodes" )
2016-10-19 13:55:39 +00:00
nodes := framework . GetReadySchedulableNodesOrDie ( f . ClientSet )
2016-08-17 04:07:17 +00:00
if len ( nodes . Items ) == 1 {
framework . Skipf ( "The test requires two Ready nodes on %s, but found just one." , framework . TestContext . Provider )
}
node1 := nodes . Items [ 0 ]
node2 := nodes . Items [ 1 ]
By ( "Creating a webserver pod be part of the TCP service which echoes back source ip" )
serverPodName := "echoserver-sourceip"
jig . launchEchoserverPodOnNode ( f , node1 . Name , serverPodName )
defer func ( ) {
framework . Logf ( "Cleaning up the echo server pod" )
2016-10-18 13:00:38 +00:00
err := cs . Core ( ) . Pods ( ns ) . Delete ( serverPodName , nil )
2016-08-17 04:07:17 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
} ( )
2016-10-05 16:13:19 +00:00
// Waiting for service to expose endpoint.
2016-10-18 13:00:38 +00:00
validateEndpointsOrFail ( cs , ns , serviceName , PortsByPodName { serverPodName : { servicePort } } )
2016-08-17 04:07:17 +00:00
By ( "Retrieve sourceip from a pod on the same node" )
2016-10-18 13:00:38 +00:00
sourceIp1 , execPodIp1 := execSourceipTest ( f , cs , ns , node1 . Name , serviceIp , servicePort )
2016-08-17 04:07:17 +00:00
By ( "Verifying the preserved source ip" )
Expect ( sourceIp1 ) . To ( Equal ( execPodIp1 ) )
By ( "Retrieve sourceip from a pod on a different node" )
2016-10-18 13:00:38 +00:00
sourceIp2 , execPodIp2 := execSourceipTest ( f , cs , ns , node2 . Name , serviceIp , servicePort )
2016-08-17 04:07:17 +00:00
By ( "Verifying the preserved source ip" )
Expect ( sourceIp2 ) . To ( Equal ( execPodIp2 ) )
} )
2015-07-16 12:38:47 +00:00
It ( "should be able to up and down services" , func ( ) {
2016-01-30 04:35:32 +00:00
// TODO: use the ServiceTestJig here
2016-04-07 17:21:31 +00:00
// this test uses framework.NodeSSHHosts that does not work if a Node only reports LegacyHostIP
framework . SkipUnlessProviderIs ( framework . ProvidersWithSSH ... )
2015-09-29 21:30:45 +00:00
ns := f . Namespace . Name
2015-07-16 12:38:47 +00:00
numPods , servicePort := 3 , 80
2016-02-03 19:06:08 +00:00
By ( "creating service1 in namespace " + ns )
2016-11-18 20:55:17 +00:00
podNames1 , svc1IP , err := startServeHostnameService ( cs , internalClientset , ns , "service1" , servicePort , numPods )
2015-07-16 12:38:47 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-02-03 19:06:08 +00:00
By ( "creating service2 in namespace " + ns )
2016-11-18 20:55:17 +00:00
podNames2 , svc2IP , err := startServeHostnameService ( cs , internalClientset , ns , "service2" , servicePort , numPods )
2015-07-16 12:38:47 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-10-18 13:00:38 +00:00
hosts , err := framework . NodeSSHHosts ( cs )
2015-07-16 12:38:47 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if len ( hosts ) == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "No ssh-able nodes" )
2015-07-16 12:38:47 +00:00
}
host := hosts [ 0 ]
2016-02-03 19:06:08 +00:00
By ( "verifying service1 is up" )
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames1 , svc1IP , servicePort ) )
2016-02-03 19:06:08 +00:00
By ( "verifying service2 is up" )
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames2 , svc2IP , servicePort ) )
2015-07-16 12:38:47 +00:00
// Stop service 1 and make sure it is gone.
2016-02-03 19:06:08 +00:00
By ( "stopping service1" )
2016-11-18 20:55:17 +00:00
framework . ExpectNoError ( stopServeHostnameService ( f . ClientSet , f . InternalClientset , ns , "service1" ) )
2015-07-16 12:38:47 +00:00
2016-02-03 19:06:08 +00:00
By ( "verifying service1 is not up" )
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceDown ( cs , host , svc1IP , servicePort ) )
2016-02-03 19:06:08 +00:00
By ( "verifying service2 is still up" )
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames2 , svc2IP , servicePort ) )
2015-07-16 12:38:47 +00:00
// Start another service and verify both are up.
2016-02-03 19:06:08 +00:00
By ( "creating service3 in namespace " + ns )
2016-11-18 20:55:17 +00:00
podNames3 , svc3IP , err := startServeHostnameService ( cs , internalClientset , ns , "service3" , servicePort , numPods )
2015-07-16 12:38:47 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if svc2IP == svc3IP {
2016-04-07 17:21:31 +00:00
framework . Failf ( "service IPs conflict: %v" , svc2IP )
2015-07-16 12:38:47 +00:00
}
2016-02-03 19:06:08 +00:00
By ( "verifying service2 is still up" )
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames2 , svc2IP , servicePort ) )
2015-07-16 12:38:47 +00:00
2016-02-03 19:06:08 +00:00
By ( "verifying service3 is up" )
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames3 , svc3IP , servicePort ) )
2015-07-16 12:38:47 +00:00
} )
2015-12-18 18:41:33 +00:00
It ( "should work after restarting kube-proxy [Disruptive]" , func ( ) {
2016-01-30 04:35:32 +00:00
// TODO: use the ServiceTestJig here
2016-04-07 17:21:31 +00:00
framework . SkipUnlessProviderIs ( "gce" , "gke" )
2015-07-16 12:38:47 +00:00
2015-09-29 21:30:45 +00:00
ns := f . Namespace . Name
2015-07-16 12:38:47 +00:00
numPods , servicePort := 3 , 80
2015-09-29 21:30:45 +00:00
svc1 := "service1"
svc2 := "service2"
2016-11-18 20:55:17 +00:00
defer func ( ) { framework . ExpectNoError ( stopServeHostnameService ( f . ClientSet , f . InternalClientset , ns , svc1 ) ) } ( )
podNames1 , svc1IP , err := startServeHostnameService ( cs , internalClientset , ns , svc1 , servicePort , numPods )
2015-07-16 12:38:47 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2015-09-29 21:30:45 +00:00
2016-11-18 20:55:17 +00:00
defer func ( ) { framework . ExpectNoError ( stopServeHostnameService ( f . ClientSet , f . InternalClientset , ns , svc2 ) ) } ( )
podNames2 , svc2IP , err := startServeHostnameService ( cs , internalClientset , ns , svc2 , servicePort , numPods )
2015-07-16 12:38:47 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if svc1IP == svc2IP {
2016-04-07 17:21:31 +00:00
framework . Failf ( "VIPs conflict: %v" , svc1IP )
2015-07-16 12:38:47 +00:00
}
2016-10-18 13:00:38 +00:00
hosts , err := framework . NodeSSHHosts ( cs )
2015-07-16 12:38:47 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if len ( hosts ) == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "No ssh-able nodes" )
2015-07-16 12:38:47 +00:00
}
host := hosts [ 0 ]
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames1 , svc1IP , servicePort ) )
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames2 , svc2IP , servicePort ) )
2015-07-16 12:38:47 +00:00
2016-08-31 23:44:30 +00:00
By ( fmt . Sprintf ( "Restarting kube-proxy on %v" , host ) )
2016-04-07 17:21:31 +00:00
if err := framework . RestartKubeProxy ( host ) ; err != nil {
framework . Failf ( "error restarting kube-proxy: %v" , err )
2015-07-16 12:38:47 +00:00
}
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames1 , svc1IP , servicePort ) )
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames2 , svc2IP , servicePort ) )
2015-09-29 21:30:45 +00:00
By ( "Removing iptable rules" )
2016-04-07 17:21:31 +00:00
result , err := framework . SSH ( `
2016-02-06 05:12:33 +00:00
sudo iptables - t nat - F KUBE - SERVICES || true ;
sudo iptables - t nat - F KUBE - PORTALS - HOST || true ;
2016-04-07 17:21:31 +00:00
sudo iptables - t nat - F KUBE - PORTALS - CONTAINER || true ` , host , framework . TestContext . Provider )
2015-11-20 21:54:34 +00:00
if err != nil || result . Code != 0 {
2016-04-07 17:21:31 +00:00
framework . LogSSHResult ( result )
framework . Failf ( "couldn't remove iptable rules: %v" , err )
2015-07-16 12:38:47 +00:00
}
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames1 , svc1IP , servicePort ) )
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames2 , svc2IP , servicePort ) )
2015-07-16 12:38:47 +00:00
} )
2015-12-18 18:41:33 +00:00
It ( "should work after restarting apiserver [Disruptive]" , func ( ) {
2016-01-30 04:35:32 +00:00
// TODO: use the ServiceTestJig here
2016-05-26 16:42:47 +00:00
framework . SkipUnlessProviderIs ( "gce" , "gke" )
2015-07-16 12:38:47 +00:00
2015-09-29 21:30:45 +00:00
ns := f . Namespace . Name
2015-07-16 12:38:47 +00:00
numPods , servicePort := 3 , 80
2016-11-18 20:55:17 +00:00
defer func ( ) {
framework . ExpectNoError ( stopServeHostnameService ( f . ClientSet , f . InternalClientset , ns , "service1" ) )
} ( )
podNames1 , svc1IP , err := startServeHostnameService ( cs , internalClientset , ns , "service1" , servicePort , numPods )
2015-11-04 19:18:35 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2015-07-16 12:38:47 +00:00
2016-10-18 13:00:38 +00:00
hosts , err := framework . NodeSSHHosts ( cs )
2015-07-16 12:38:47 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if len ( hosts ) == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "No ssh-able nodes" )
2015-07-16 12:38:47 +00:00
}
host := hosts [ 0 ]
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames1 , svc1IP , servicePort ) )
2015-07-16 12:38:47 +00:00
// Restart apiserver
2016-08-31 23:44:30 +00:00
By ( "Restarting apiserver" )
2016-10-18 13:00:38 +00:00
if err := framework . RestartApiserver ( cs . Discovery ( ) ) ; err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "error restarting apiserver: %v" , err )
2015-07-16 12:38:47 +00:00
}
2016-08-31 23:44:30 +00:00
By ( "Waiting for apiserver to come up by polling /healthz" )
2016-10-18 13:00:38 +00:00
if err := framework . WaitForApiserverUp ( cs ) ; err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "error while waiting for apiserver up: %v" , err )
2015-07-16 12:38:47 +00:00
}
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames1 , svc1IP , servicePort ) )
2015-07-16 12:38:47 +00:00
// Create a new service and check if it's not reusing IP.
2016-11-18 20:55:17 +00:00
defer func ( ) {
framework . ExpectNoError ( stopServeHostnameService ( f . ClientSet , f . InternalClientset , ns , "service2" ) )
} ( )
podNames2 , svc2IP , err := startServeHostnameService ( cs , internalClientset , ns , "service2" , servicePort , numPods )
2015-11-04 19:18:35 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2015-07-16 12:38:47 +00:00
if svc1IP == svc2IP {
2016-04-07 17:21:31 +00:00
framework . Failf ( "VIPs conflict: %v" , svc1IP )
2015-07-16 12:38:47 +00:00
}
2016-10-18 13:00:38 +00:00
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames1 , svc1IP , servicePort ) )
framework . ExpectNoError ( verifyServeHostnameServiceUp ( cs , ns , host , podNames2 , svc2IP , servicePort ) )
2015-07-16 12:38:47 +00:00
} )
2015-12-16 22:35:10 +00:00
// TODO: Run this test against the userspace proxy and nodes
// configured with a default deny firewall to validate that the
// proxy whitelists NodePort traffic.
2015-05-20 15:59:34 +00:00
It ( "should be able to create a functioning NodePort service" , func ( ) {
2016-01-30 04:35:32 +00:00
serviceName := "nodeport-test"
2015-09-29 21:30:45 +00:00
ns := f . Namespace . Name
2015-05-20 15:59:34 +00:00
2016-10-18 13:00:38 +00:00
jig := NewServiceTestJig ( cs , serviceName )
nodeIP := pickNodeIP ( jig . Client ) // for later
2015-05-22 23:01:35 +00:00
By ( "creating service " + serviceName + " with type=NodePort in namespace " + ns )
2016-11-18 20:55:17 +00:00
service := jig . CreateTCPServiceOrFail ( ns , func ( svc * v1 . Service ) {
svc . Spec . Type = v1 . ServiceTypeNodePort
2016-01-30 04:35:32 +00:00
} )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( service , v1 . ServiceTypeNodePort )
2016-04-27 04:35:14 +00:00
nodePort := int ( service . Spec . Ports [ 0 ] . NodePort )
2015-05-22 23:01:35 +00:00
By ( "creating pod to be part of service " + serviceName )
2016-01-30 04:35:32 +00:00
jig . RunOrFail ( ns , nil )
2015-05-22 23:01:35 +00:00
By ( "hitting the pod through the service's NodePort" )
2016-01-30 04:35:32 +00:00
jig . TestReachableHTTP ( nodeIP , nodePort , kubeProxyLagTimeout )
2015-06-17 22:26:14 +00:00
2015-12-05 00:35:02 +00:00
By ( "verifying the node port is locked" )
2016-10-18 13:00:38 +00:00
hostExec := framework . LaunchHostExecPod ( f . ClientSet , f . Namespace . Name , "hostexec" )
2016-01-27 21:42:00 +00:00
// Even if the node-ip:node-port check above passed, this hostexec pod
// might fall on a node with a laggy kube-proxy.
cmd := fmt . Sprintf ( ` for i in $(seq 1 300); do if ss -ant46 'sport = :%d' | grep ^LISTEN; then exit 0; fi; sleep 1; done; exit 1 ` , nodePort )
2016-04-07 17:21:31 +00:00
stdout , err := framework . RunHostCmd ( hostExec . Namespace , hostExec . Name , cmd )
2015-11-12 23:30:21 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "expected node port %d to be in use, stdout: %v. err: %v" , nodePort , stdout , err )
2015-06-17 22:26:14 +00:00
}
2015-05-22 23:01:35 +00:00
} )
2016-04-07 00:26:16 +00:00
It ( "should be able to change the type and ports of a service [Slow]" , func ( ) {
2015-09-29 21:30:45 +00:00
// requires cloud load-balancer support
2016-04-07 17:21:31 +00:00
framework . SkipUnlessProviderIs ( "gce" , "gke" , "aws" )
2015-07-09 16:47:12 +00:00
2016-04-07 17:21:31 +00:00
loadBalancerSupportsUDP := ! framework . ProviderIs ( "aws" )
2016-02-10 02:59:35 +00:00
2016-02-10 14:31:52 +00:00
loadBalancerLagTimeout := loadBalancerLagTimeoutDefault
2016-04-07 17:21:31 +00:00
if framework . ProviderIs ( "aws" ) {
2016-02-10 14:31:52 +00:00
loadBalancerLagTimeout = loadBalancerLagTimeoutAWS
}
2016-08-02 10:30:14 +00:00
loadBalancerCreateTimeout := loadBalancerCreateTimeoutDefault
largeClusterMinNodesNumber := 100
2016-10-19 13:55:39 +00:00
if nodes := framework . GetReadySchedulableNodesOrDie ( cs ) ; len ( nodes . Items ) > largeClusterMinNodesNumber {
2016-08-02 10:30:14 +00:00
loadBalancerCreateTimeout = loadBalancerCreateTimeoutLarge
}
2016-02-10 14:31:52 +00:00
2016-01-30 04:35:32 +00:00
// This test is more monolithic than we'd like because LB turnup can be
// very slow, so we lumped all the tests into one LB lifecycle.
2015-05-22 23:01:35 +00:00
2016-01-30 04:35:32 +00:00
serviceName := "mutability-test"
ns1 := f . Namespace . Name // LB1 in ns1 on TCP
2016-04-07 17:21:31 +00:00
framework . Logf ( "namespace for TCP test: %s" , ns1 )
2015-05-22 23:01:35 +00:00
2016-01-30 04:35:32 +00:00
By ( "creating a second namespace" )
2016-02-06 05:38:52 +00:00
namespacePtr , err := f . CreateNamespace ( "services" , nil )
2015-05-20 15:59:34 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-01-30 04:35:32 +00:00
ns2 := namespacePtr . Name // LB2 in ns2 on UDP
2016-04-07 17:21:31 +00:00
framework . Logf ( "namespace for UDP test: %s" , ns2 )
2015-05-22 23:01:35 +00:00
2016-10-18 13:00:38 +00:00
jig := NewServiceTestJig ( cs , serviceName )
nodeIP := pickNodeIP ( jig . Client ) // for later
2016-01-30 04:35:32 +00:00
// Test TCP and UDP Services. Services with the same name in different
// namespaces should get different node ports and load balancers.
By ( "creating a TCP service " + serviceName + " with type=ClusterIP in namespace " + ns1 )
tcpService := jig . CreateTCPServiceOrFail ( ns1 , nil )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( tcpService , v1 . ServiceTypeClusterIP )
2016-01-30 04:35:32 +00:00
By ( "creating a UDP service " + serviceName + " with type=ClusterIP in namespace " + ns2 )
udpService := jig . CreateUDPServiceOrFail ( ns2 , nil )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( udpService , v1 . ServiceTypeClusterIP )
2016-01-30 04:35:32 +00:00
By ( "verifying that TCP and UDP use the same port" )
if tcpService . Spec . Ports [ 0 ] . Port != udpService . Spec . Ports [ 0 ] . Port {
2016-04-07 17:21:31 +00:00
framework . Failf ( "expected to use the same port for TCP and UDP" )
2015-05-20 15:59:34 +00:00
}
2016-04-27 04:35:14 +00:00
svcPort := int ( tcpService . Spec . Ports [ 0 ] . Port )
2016-04-07 17:21:31 +00:00
framework . Logf ( "service port (TCP and UDP): %d" , svcPort )
2016-01-30 04:35:32 +00:00
By ( "creating a pod to be part of the TCP service " + serviceName )
jig . RunOrFail ( ns1 , nil )
2015-05-20 15:59:34 +00:00
2016-01-30 04:35:32 +00:00
By ( "creating a pod to be part of the UDP service " + serviceName )
jig . RunOrFail ( ns2 , nil )
2015-05-22 23:01:35 +00:00
2016-01-30 04:35:32 +00:00
// Change the services to NodePort.
2016-02-04 17:28:48 +00:00
By ( "changing the TCP service to type=NodePort" )
2016-11-18 20:55:17 +00:00
tcpService = jig . UpdateServiceOrFail ( ns1 , tcpService . Name , func ( s * v1 . Service ) {
s . Spec . Type = v1 . ServiceTypeNodePort
2015-07-10 20:38:37 +00:00
} )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( tcpService , v1 . ServiceTypeNodePort )
2016-04-27 04:35:14 +00:00
tcpNodePort := int ( tcpService . Spec . Ports [ 0 ] . NodePort )
2016-04-07 17:21:31 +00:00
framework . Logf ( "TCP node port: %d" , tcpNodePort )
2015-05-22 23:01:35 +00:00
2016-02-04 17:28:48 +00:00
By ( "changing the UDP service to type=NodePort" )
2016-11-18 20:55:17 +00:00
udpService = jig . UpdateServiceOrFail ( ns2 , udpService . Name , func ( s * v1 . Service ) {
s . Spec . Type = v1 . ServiceTypeNodePort
2016-01-30 04:35:32 +00:00
} )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( udpService , v1 . ServiceTypeNodePort )
2016-04-27 04:35:14 +00:00
udpNodePort := int ( udpService . Spec . Ports [ 0 ] . NodePort )
2016-04-07 17:21:31 +00:00
framework . Logf ( "UDP node port: %d" , udpNodePort )
2015-09-29 21:30:45 +00:00
2016-01-30 04:35:32 +00:00
By ( "hitting the TCP service's NodePort" )
jig . TestReachableHTTP ( nodeIP , tcpNodePort , kubeProxyLagTimeout )
2016-01-27 21:42:00 +00:00
2016-01-30 04:35:32 +00:00
By ( "hitting the UDP service's NodePort" )
jig . TestReachableUDP ( nodeIP , udpNodePort , kubeProxyLagTimeout )
// Change the services to LoadBalancer.
2016-04-06 22:12:31 +00:00
// Here we test that LoadBalancers can receive static IP addresses. This isn't
// necessary, but is an additional feature this monolithic test checks.
2016-01-30 04:35:32 +00:00
requestedIP := ""
2016-02-04 18:51:41 +00:00
staticIPName := ""
2016-04-07 17:21:31 +00:00
if framework . ProviderIs ( "gce" , "gke" ) {
2016-01-30 04:35:32 +00:00
By ( "creating a static load balancer IP" )
2016-04-07 17:21:31 +00:00
staticIPName = fmt . Sprintf ( "e2e-external-lb-test-%s" , framework . RunId )
2016-01-30 04:35:32 +00:00
requestedIP , err = createGCEStaticIP ( staticIPName )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
defer func ( ) {
2016-02-04 18:51:41 +00:00
if staticIPName != "" {
// Release GCE static IP - this is not kube-managed and will not be automatically released.
if err := deleteGCEStaticIP ( staticIPName ) ; err != nil {
2016-04-07 17:21:31 +00:00
framework . Logf ( "failed to release static IP %s: %v" , staticIPName , err )
2016-02-04 18:51:41 +00:00
}
}
2016-01-30 04:35:32 +00:00
} ( )
2016-04-07 17:21:31 +00:00
framework . Logf ( "Allocated static load balancer IP: %s" , requestedIP )
2016-01-27 21:42:00 +00:00
}
2015-05-22 23:01:35 +00:00
2016-02-04 17:28:48 +00:00
By ( "changing the TCP service to type=LoadBalancer" )
2016-11-18 20:55:17 +00:00
tcpService = jig . UpdateServiceOrFail ( ns1 , tcpService . Name , func ( s * v1 . Service ) {
2016-01-30 04:35:32 +00:00
s . Spec . LoadBalancerIP = requestedIP // will be "" if not applicable
2016-11-18 20:55:17 +00:00
s . Spec . Type = v1 . ServiceTypeLoadBalancer
2015-07-10 20:38:37 +00:00
} )
2015-05-22 23:01:35 +00:00
2016-02-10 02:59:35 +00:00
if loadBalancerSupportsUDP {
By ( "changing the UDP service to type=LoadBalancer" )
2016-11-18 20:55:17 +00:00
udpService = jig . UpdateServiceOrFail ( ns2 , udpService . Name , func ( s * v1 . Service ) {
s . Spec . Type = v1 . ServiceTypeLoadBalancer
2016-02-10 02:59:35 +00:00
} )
}
2016-09-07 02:48:04 +00:00
serviceLBNames = append ( serviceLBNames , getLoadBalancerName ( tcpService ) )
if loadBalancerSupportsUDP {
serviceLBNames = append ( serviceLBNames , getLoadBalancerName ( udpService ) )
}
2015-05-22 23:01:35 +00:00
2016-02-04 17:28:48 +00:00
By ( "waiting for the TCP service to have a load balancer" )
2016-01-30 04:35:32 +00:00
// Wait for the load balancer to be created asynchronously
2016-08-02 10:30:14 +00:00
tcpService = jig . WaitForLoadBalancerOrFail ( ns1 , tcpService . Name , loadBalancerCreateTimeout )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( tcpService , v1 . ServiceTypeLoadBalancer )
2016-04-27 04:35:14 +00:00
if int ( tcpService . Spec . Ports [ 0 ] . NodePort ) != tcpNodePort {
2016-04-07 17:21:31 +00:00
framework . Failf ( "TCP Spec.Ports[0].NodePort changed (%d -> %d) when not expected" , tcpNodePort , tcpService . Spec . Ports [ 0 ] . NodePort )
2015-05-22 23:01:35 +00:00
}
2016-01-30 04:35:32 +00:00
if requestedIP != "" && getIngressPoint ( & tcpService . Status . LoadBalancer . Ingress [ 0 ] ) != requestedIP {
2016-04-07 17:21:31 +00:00
framework . Failf ( "unexpected TCP Status.LoadBalancer.Ingress (expected %s, got %s)" , requestedIP , getIngressPoint ( & tcpService . Status . LoadBalancer . Ingress [ 0 ] ) )
2015-05-22 23:01:35 +00:00
}
2016-01-30 04:35:32 +00:00
tcpIngressIP := getIngressPoint ( & tcpService . Status . LoadBalancer . Ingress [ 0 ] )
2016-04-07 17:21:31 +00:00
framework . Logf ( "TCP load balancer: %s" , tcpIngressIP )
2016-01-30 04:35:32 +00:00
2016-04-07 17:21:31 +00:00
if framework . ProviderIs ( "gce" , "gke" ) {
2016-02-04 18:51:41 +00:00
// Do this as early as possible, which overrides the `defer` above.
// This is mostly out of fear of leaking the IP in a timeout case
// (as of this writing we're not 100% sure where the leaks are
// coming from, so this is first-aid rather than surgery).
By ( "demoting the static IP to ephemeral" )
if staticIPName != "" {
// Deleting it after it is attached "demotes" it to an
// ephemeral IP, which can be auto-released.
if err := deleteGCEStaticIP ( staticIPName ) ; err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "failed to release static IP %s: %v" , staticIPName , err )
2016-02-04 18:51:41 +00:00
}
staticIPName = ""
}
}
2016-02-10 02:59:35 +00:00
var udpIngressIP string
if loadBalancerSupportsUDP {
By ( "waiting for the UDP service to have a load balancer" )
// 2nd one should be faster since they ran in parallel.
2016-08-02 10:30:14 +00:00
udpService = jig . WaitForLoadBalancerOrFail ( ns2 , udpService . Name , loadBalancerCreateTimeout )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( udpService , v1 . ServiceTypeLoadBalancer )
2016-04-27 04:35:14 +00:00
if int ( udpService . Spec . Ports [ 0 ] . NodePort ) != udpNodePort {
2016-04-07 17:21:31 +00:00
framework . Failf ( "UDP Spec.Ports[0].NodePort changed (%d -> %d) when not expected" , udpNodePort , udpService . Spec . Ports [ 0 ] . NodePort )
2016-02-10 02:59:35 +00:00
}
udpIngressIP = getIngressPoint ( & udpService . Status . LoadBalancer . Ingress [ 0 ] )
2016-04-07 17:21:31 +00:00
framework . Logf ( "UDP load balancer: %s" , udpIngressIP )
2015-09-29 21:30:45 +00:00
2016-02-10 02:59:35 +00:00
By ( "verifying that TCP and UDP use different load balancers" )
if tcpIngressIP == udpIngressIP {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Load balancers are not different: %s" , getIngressPoint ( & tcpService . Status . LoadBalancer . Ingress [ 0 ] ) )
2016-02-10 02:59:35 +00:00
}
2015-05-22 23:01:35 +00:00
}
2016-01-30 04:35:32 +00:00
By ( "hitting the TCP service's NodePort" )
jig . TestReachableHTTP ( nodeIP , tcpNodePort , kubeProxyLagTimeout )
By ( "hitting the UDP service's NodePort" )
jig . TestReachableUDP ( nodeIP , udpNodePort , kubeProxyLagTimeout )
By ( "hitting the TCP service's LoadBalancer" )
jig . TestReachableHTTP ( tcpIngressIP , svcPort , loadBalancerLagTimeout )
2016-02-10 02:59:35 +00:00
if loadBalancerSupportsUDP {
By ( "hitting the UDP service's LoadBalancer" )
jig . TestReachableUDP ( udpIngressIP , svcPort , loadBalancerLagTimeout )
}
2016-01-30 04:35:32 +00:00
// Change the services' node ports.
2016-02-04 17:28:48 +00:00
By ( "changing the TCP service's NodePort" )
2016-01-30 04:35:32 +00:00
tcpService = jig . ChangeServiceNodePortOrFail ( ns1 , tcpService . Name , tcpNodePort )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( tcpService , v1 . ServiceTypeLoadBalancer )
2016-01-30 04:35:32 +00:00
tcpNodePortOld := tcpNodePort
2016-04-27 04:35:14 +00:00
tcpNodePort = int ( tcpService . Spec . Ports [ 0 ] . NodePort )
2016-01-30 04:35:32 +00:00
if tcpNodePort == tcpNodePortOld {
2016-04-07 17:21:31 +00:00
framework . Failf ( "TCP Spec.Ports[0].NodePort (%d) did not change" , tcpNodePort )
2015-05-22 23:01:35 +00:00
}
2016-01-30 04:35:32 +00:00
if getIngressPoint ( & tcpService . Status . LoadBalancer . Ingress [ 0 ] ) != tcpIngressIP {
2016-04-07 17:21:31 +00:00
framework . Failf ( "TCP Status.LoadBalancer.Ingress changed (%s -> %s) when not expected" , tcpIngressIP , getIngressPoint ( & tcpService . Status . LoadBalancer . Ingress [ 0 ] ) )
2015-05-22 23:01:35 +00:00
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "TCP node port: %d" , tcpNodePort )
2016-01-30 04:35:32 +00:00
2016-02-04 17:28:48 +00:00
By ( "changing the UDP service's NodePort" )
2016-01-30 04:35:32 +00:00
udpService = jig . ChangeServiceNodePortOrFail ( ns2 , udpService . Name , udpNodePort )
2016-02-10 02:59:35 +00:00
if loadBalancerSupportsUDP {
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( udpService , v1 . ServiceTypeLoadBalancer )
2016-02-10 02:59:35 +00:00
} else {
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( udpService , v1 . ServiceTypeNodePort )
2016-02-10 02:59:35 +00:00
}
2016-01-30 04:35:32 +00:00
udpNodePortOld := udpNodePort
2016-04-27 04:35:14 +00:00
udpNodePort = int ( udpService . Spec . Ports [ 0 ] . NodePort )
2016-01-30 04:35:32 +00:00
if udpNodePort == udpNodePortOld {
2016-04-07 17:21:31 +00:00
framework . Failf ( "UDP Spec.Ports[0].NodePort (%d) did not change" , udpNodePort )
2015-05-22 23:01:35 +00:00
}
2016-02-10 02:59:35 +00:00
if loadBalancerSupportsUDP && getIngressPoint ( & udpService . Status . LoadBalancer . Ingress [ 0 ] ) != udpIngressIP {
2016-04-07 17:21:31 +00:00
framework . Failf ( "UDP Status.LoadBalancer.Ingress changed (%s -> %s) when not expected" , udpIngressIP , getIngressPoint ( & udpService . Status . LoadBalancer . Ingress [ 0 ] ) )
2015-05-22 23:01:35 +00:00
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "UDP node port: %d" , udpNodePort )
2015-07-09 17:31:30 +00:00
2016-01-30 04:35:32 +00:00
By ( "hitting the TCP service's new NodePort" )
jig . TestReachableHTTP ( nodeIP , tcpNodePort , kubeProxyLagTimeout )
2016-01-27 21:42:00 +00:00
2016-01-30 04:35:32 +00:00
By ( "hitting the UDP service's new NodePort" )
jig . TestReachableUDP ( nodeIP , udpNodePort , kubeProxyLagTimeout )
2016-01-27 21:42:00 +00:00
2016-01-30 04:35:32 +00:00
By ( "checking the old TCP NodePort is closed" )
jig . TestNotReachableHTTP ( nodeIP , tcpNodePortOld , kubeProxyLagTimeout )
2015-05-22 23:01:35 +00:00
2016-01-30 04:35:32 +00:00
By ( "checking the old UDP NodePort is closed" )
jig . TestNotReachableUDP ( nodeIP , udpNodePortOld , kubeProxyLagTimeout )
2015-09-29 21:30:45 +00:00
2016-01-30 04:35:32 +00:00
By ( "hitting the TCP service's LoadBalancer" )
jig . TestReachableHTTP ( tcpIngressIP , svcPort , loadBalancerLagTimeout )
2015-09-29 21:30:45 +00:00
2016-02-10 02:59:35 +00:00
if loadBalancerSupportsUDP {
By ( "hitting the UDP service's LoadBalancer" )
jig . TestReachableUDP ( udpIngressIP , svcPort , loadBalancerLagTimeout )
}
2016-01-30 04:35:32 +00:00
// Change the services' main ports.
By ( "changing the TCP service's port" )
2016-11-18 20:55:17 +00:00
tcpService = jig . UpdateServiceOrFail ( ns1 , tcpService . Name , func ( s * v1 . Service ) {
2016-01-30 04:35:32 +00:00
s . Spec . Ports [ 0 ] . Port ++
} )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( tcpService , v1 . ServiceTypeLoadBalancer )
2016-01-30 04:35:32 +00:00
svcPortOld := svcPort
2016-04-27 04:35:14 +00:00
svcPort = int ( tcpService . Spec . Ports [ 0 ] . Port )
2016-01-30 04:35:32 +00:00
if svcPort == svcPortOld {
2016-04-07 17:21:31 +00:00
framework . Failf ( "TCP Spec.Ports[0].Port (%d) did not change" , svcPort )
2016-01-30 04:35:32 +00:00
}
2016-04-27 04:35:14 +00:00
if int ( tcpService . Spec . Ports [ 0 ] . NodePort ) != tcpNodePort {
2016-04-07 17:21:31 +00:00
framework . Failf ( "TCP Spec.Ports[0].NodePort (%d) changed" , tcpService . Spec . Ports [ 0 ] . NodePort )
2015-09-29 21:30:45 +00:00
}
2016-01-30 04:35:32 +00:00
if getIngressPoint ( & tcpService . Status . LoadBalancer . Ingress [ 0 ] ) != tcpIngressIP {
2016-04-07 17:21:31 +00:00
framework . Failf ( "TCP Status.LoadBalancer.Ingress changed (%s -> %s) when not expected" , tcpIngressIP , getIngressPoint ( & tcpService . Status . LoadBalancer . Ingress [ 0 ] ) )
2016-01-30 04:35:32 +00:00
}
2015-09-29 21:30:45 +00:00
2016-01-30 04:35:32 +00:00
By ( "changing the UDP service's port" )
2016-11-18 20:55:17 +00:00
udpService = jig . UpdateServiceOrFail ( ns2 , udpService . Name , func ( s * v1 . Service ) {
2016-01-30 04:35:32 +00:00
s . Spec . Ports [ 0 ] . Port ++
2015-10-13 18:28:36 +00:00
} )
2016-02-10 02:59:35 +00:00
if loadBalancerSupportsUDP {
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( udpService , v1 . ServiceTypeLoadBalancer )
2016-02-10 02:59:35 +00:00
} else {
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( udpService , v1 . ServiceTypeNodePort )
2016-02-10 02:59:35 +00:00
}
2016-04-27 04:35:14 +00:00
if int ( udpService . Spec . Ports [ 0 ] . Port ) != svcPort {
2016-04-07 17:21:31 +00:00
framework . Failf ( "UDP Spec.Ports[0].Port (%d) did not change" , udpService . Spec . Ports [ 0 ] . Port )
2015-10-13 18:28:36 +00:00
}
2016-04-27 04:35:14 +00:00
if int ( udpService . Spec . Ports [ 0 ] . NodePort ) != udpNodePort {
2016-04-07 17:21:31 +00:00
framework . Failf ( "UDP Spec.Ports[0].NodePort (%d) changed" , udpService . Spec . Ports [ 0 ] . NodePort )
2016-01-30 04:35:32 +00:00
}
2016-02-10 02:59:35 +00:00
if loadBalancerSupportsUDP && getIngressPoint ( & udpService . Status . LoadBalancer . Ingress [ 0 ] ) != udpIngressIP {
2016-04-07 17:21:31 +00:00
framework . Failf ( "UDP Status.LoadBalancer.Ingress changed (%s -> %s) when not expected" , udpIngressIP , getIngressPoint ( & udpService . Status . LoadBalancer . Ingress [ 0 ] ) )
2016-01-30 04:35:32 +00:00
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "service port (TCP and UDP): %d" , svcPort )
2016-02-04 18:51:41 +00:00
2016-01-30 04:35:32 +00:00
By ( "hitting the TCP service's NodePort" )
jig . TestReachableHTTP ( nodeIP , tcpNodePort , kubeProxyLagTimeout )
By ( "hitting the UDP service's NodePort" )
jig . TestReachableUDP ( nodeIP , udpNodePort , kubeProxyLagTimeout )
By ( "hitting the TCP service's LoadBalancer" )
jig . TestReachableHTTP ( tcpIngressIP , svcPort , loadBalancerCreateTimeout ) // this may actually recreate the LB
2016-02-10 02:59:35 +00:00
if loadBalancerSupportsUDP {
By ( "hitting the UDP service's LoadBalancer" )
jig . TestReachableUDP ( udpIngressIP , svcPort , loadBalancerCreateTimeout ) // this may actually recreate the LB)
}
2016-01-30 04:35:32 +00:00
// Change the services back to ClusterIP.
2016-02-04 17:28:48 +00:00
By ( "changing TCP service back to type=ClusterIP" )
2016-11-18 20:55:17 +00:00
tcpService = jig . UpdateServiceOrFail ( ns1 , tcpService . Name , func ( s * v1 . Service ) {
s . Spec . Type = v1 . ServiceTypeClusterIP
2016-01-30 04:35:32 +00:00
s . Spec . Ports [ 0 ] . NodePort = 0
} )
// Wait for the load balancer to be destroyed asynchronously
2016-08-02 10:30:14 +00:00
tcpService = jig . WaitForLoadBalancerDestroyOrFail ( ns1 , tcpService . Name , tcpIngressIP , svcPort , loadBalancerCreateTimeout )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( tcpService , v1 . ServiceTypeClusterIP )
2016-01-30 04:35:32 +00:00
2016-02-04 17:28:48 +00:00
By ( "changing UDP service back to type=ClusterIP" )
2016-11-18 20:55:17 +00:00
udpService = jig . UpdateServiceOrFail ( ns2 , udpService . Name , func ( s * v1 . Service ) {
s . Spec . Type = v1 . ServiceTypeClusterIP
2016-01-30 04:35:32 +00:00
s . Spec . Ports [ 0 ] . NodePort = 0
} )
2016-02-10 02:59:35 +00:00
if loadBalancerSupportsUDP {
// Wait for the load balancer to be destroyed asynchronously
2016-08-02 10:30:14 +00:00
udpService = jig . WaitForLoadBalancerDestroyOrFail ( ns2 , udpService . Name , udpIngressIP , svcPort , loadBalancerCreateTimeout )
2016-11-18 20:55:17 +00:00
jig . SanityCheckService ( udpService , v1 . ServiceTypeClusterIP )
2016-02-10 02:59:35 +00:00
}
2015-10-13 18:28:36 +00:00
2016-01-30 04:35:32 +00:00
By ( "checking the TCP NodePort is closed" )
jig . TestNotReachableHTTP ( nodeIP , tcpNodePort , kubeProxyLagTimeout )
2015-05-22 23:01:35 +00:00
2016-01-30 04:35:32 +00:00
By ( "checking the UDP NodePort is closed" )
jig . TestNotReachableUDP ( nodeIP , udpNodePort , kubeProxyLagTimeout )
By ( "checking the TCP LoadBalancer is closed" )
jig . TestNotReachableHTTP ( tcpIngressIP , svcPort , loadBalancerLagTimeout )
2016-02-10 02:59:35 +00:00
if loadBalancerSupportsUDP {
By ( "checking the UDP LoadBalancer is closed" )
jig . TestNotReachableUDP ( udpIngressIP , svcPort , loadBalancerLagTimeout )
}
2015-05-22 23:01:35 +00:00
} )
2016-08-20 00:45:09 +00:00
It ( "should use same NodePort with same port but different protocols" , func ( ) {
serviceName := "nodeports"
ns := f . Namespace . Name
2016-10-18 13:00:38 +00:00
t := NewServerTest ( cs , ns , serviceName )
2016-08-20 00:45:09 +00:00
defer func ( ) {
defer GinkgoRecover ( )
errs := t . Cleanup ( )
if len ( errs ) != 0 {
framework . Failf ( "errors in cleanup: %v" , errs )
}
} ( )
By ( "creating service " + serviceName + " with same NodePort but different protocols in namespace " + ns )
2016-11-18 20:55:17 +00:00
service := & v1 . Service {
ObjectMeta : v1 . ObjectMeta {
2016-08-20 00:45:09 +00:00
Name : t . ServiceName ,
Namespace : t . Namespace ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . ServiceSpec {
2016-08-20 00:45:09 +00:00
Selector : t . Labels ,
2016-11-18 20:55:17 +00:00
Type : v1 . ServiceTypeNodePort ,
Ports : [ ] v1 . ServicePort {
2016-08-20 00:45:09 +00:00
{
Name : "tcp-port" ,
Port : 53 ,
2016-11-18 20:55:17 +00:00
Protocol : v1 . ProtocolTCP ,
2016-08-20 00:45:09 +00:00
} ,
{
Name : "udp-port" ,
Port : 53 ,
2016-11-18 20:55:17 +00:00
Protocol : v1 . ProtocolUDP ,
2016-08-20 00:45:09 +00:00
} ,
} ,
} ,
}
result , err := t . CreateService ( service )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if len ( result . Spec . Ports ) != 2 {
framework . Failf ( "got unexpected len(Spec.Ports) for new service: %v" , result )
}
if result . Spec . Ports [ 0 ] . NodePort != result . Spec . Ports [ 1 ] . NodePort {
framework . Failf ( "should use same NodePort for new service: %v" , result )
}
} )
2015-05-22 23:01:35 +00:00
It ( "should prevent NodePort collisions" , func ( ) {
2016-01-30 04:35:32 +00:00
// TODO: use the ServiceTestJig here
2015-09-29 21:30:45 +00:00
baseName := "nodeport-collision-"
serviceName1 := baseName + "1"
serviceName2 := baseName + "2"
ns := f . Namespace . Name
2015-05-22 23:01:35 +00:00
2016-10-18 13:00:38 +00:00
t := NewServerTest ( cs , ns , serviceName1 )
2015-05-22 23:01:35 +00:00
defer func ( ) {
defer GinkgoRecover ( )
errs := t . Cleanup ( )
if len ( errs ) != 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "errors in cleanup: %v" , errs )
2015-05-22 23:01:35 +00:00
}
} ( )
2015-09-29 21:30:45 +00:00
By ( "creating service " + serviceName1 + " with type NodePort in namespace " + ns )
2015-05-22 23:01:35 +00:00
service := t . BuildServiceSpec ( )
2016-11-18 20:55:17 +00:00
service . Spec . Type = v1 . ServiceTypeNodePort
2015-05-22 23:01:35 +00:00
result , err := t . CreateService ( service )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-11-18 20:55:17 +00:00
if result . Spec . Type != v1 . ServiceTypeNodePort {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected Spec.Type for new service: %v" , result )
2015-05-22 23:01:35 +00:00
}
if len ( result . Spec . Ports ) != 1 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected len(Spec.Ports) for new service: %v" , result )
2015-05-22 23:01:35 +00:00
}
port := result . Spec . Ports [ 0 ]
if port . NodePort == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected Spec.Ports[0].nodePort for new service: %v" , result )
2015-05-22 23:01:35 +00:00
}
2015-09-29 21:30:45 +00:00
By ( "creating service " + serviceName2 + " with conflicting NodePort" )
2015-05-22 23:01:35 +00:00
service2 := t . BuildServiceSpec ( )
service2 . Name = serviceName2
2016-11-18 20:55:17 +00:00
service2 . Spec . Type = v1 . ServiceTypeNodePort
2015-05-22 23:01:35 +00:00
service2 . Spec . Ports [ 0 ] . NodePort = port . NodePort
result2 , err := t . CreateService ( service2 )
if err == nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Created service with conflicting NodePort: %v" , result2 )
2015-05-22 23:01:35 +00:00
}
2016-01-20 05:13:39 +00:00
expectedErr := fmt . Sprintf ( "%d.*port is already allocated" , port . NodePort )
Expect ( fmt . Sprintf ( "%v" , err ) ) . To ( MatchRegexp ( expectedErr ) )
2015-05-22 23:01:35 +00:00
2015-09-29 21:30:45 +00:00
By ( "deleting service " + serviceName1 + " to release NodePort" )
err = t . DeleteService ( serviceName1 )
2015-05-22 23:01:35 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
By ( "creating service " + serviceName2 + " with no-longer-conflicting NodePort" )
_ , err = t . CreateService ( service2 )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
} )
It ( "should check NodePort out-of-range" , func ( ) {
2016-01-30 04:35:32 +00:00
// TODO: use the ServiceTestJig here
2015-05-22 23:01:35 +00:00
serviceName := "nodeport-range-test"
2015-09-29 21:30:45 +00:00
ns := f . Namespace . Name
2015-05-22 23:01:35 +00:00
2016-10-18 13:00:38 +00:00
t := NewServerTest ( cs , ns , serviceName )
2015-05-20 15:59:34 +00:00
defer func ( ) {
defer GinkgoRecover ( )
2015-05-22 23:01:35 +00:00
errs := t . Cleanup ( )
if len ( errs ) != 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "errors in cleanup: %v" , errs )
2015-05-22 23:01:35 +00:00
}
2015-05-20 15:59:34 +00:00
} ( )
2015-05-22 23:01:35 +00:00
service := t . BuildServiceSpec ( )
2016-11-18 20:55:17 +00:00
service . Spec . Type = v1 . ServiceTypeNodePort
2015-05-22 23:01:35 +00:00
By ( "creating service " + serviceName + " with type NodePort in namespace " + ns )
service , err := t . CreateService ( service )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-11-18 20:55:17 +00:00
if service . Spec . Type != v1 . ServiceTypeNodePort {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected Spec.Type for new service: %v" , service )
2015-05-22 23:01:35 +00:00
}
if len ( service . Spec . Ports ) != 1 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected len(Spec.Ports) for new service: %v" , service )
2015-05-22 23:01:35 +00:00
}
port := service . Spec . Ports [ 0 ]
if port . NodePort == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected Spec.Ports[0].nodePort for new service: %v" , service )
2015-05-22 23:01:35 +00:00
}
2016-04-27 04:35:14 +00:00
if ! ServiceNodePortRange . Contains ( int ( port . NodePort ) ) {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected (out-of-range) port for new service: %v" , service )
2015-05-20 15:59:34 +00:00
}
2015-05-22 23:01:35 +00:00
outOfRangeNodePort := 0
2016-02-11 03:42:17 +00:00
rand . Seed ( time . Now ( ) . UTC ( ) . UnixNano ( ) )
2015-05-22 23:01:35 +00:00
for {
outOfRangeNodePort = 1 + rand . Intn ( 65535 )
if ! ServiceNodePortRange . Contains ( outOfRangeNodePort ) {
2015-05-20 15:59:34 +00:00
break
}
}
2015-05-22 23:01:35 +00:00
By ( fmt . Sprintf ( "changing service " + serviceName + " to out-of-range NodePort %d" , outOfRangeNodePort ) )
2016-11-18 20:55:17 +00:00
result , err := updateService ( cs , ns , serviceName , func ( s * v1 . Service ) {
2016-04-27 04:35:14 +00:00
s . Spec . Ports [ 0 ] . NodePort = int32 ( outOfRangeNodePort )
2015-07-10 20:38:37 +00:00
} )
2015-05-22 23:01:35 +00:00
if err == nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "failed to prevent update of service with out-of-range NodePort: %v" , result )
2015-05-22 23:01:35 +00:00
}
2016-01-20 05:13:39 +00:00
expectedErr := fmt . Sprintf ( "%d.*port is not in the valid range" , outOfRangeNodePort )
Expect ( fmt . Sprintf ( "%v" , err ) ) . To ( MatchRegexp ( expectedErr ) )
2015-05-22 23:01:35 +00:00
By ( "deleting original service " + serviceName )
err = t . DeleteService ( serviceName )
2015-05-20 15:59:34 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2015-05-22 23:01:35 +00:00
By ( fmt . Sprintf ( "creating service " + serviceName + " with out-of-range NodePort %d" , outOfRangeNodePort ) )
service = t . BuildServiceSpec ( )
2016-11-18 20:55:17 +00:00
service . Spec . Type = v1 . ServiceTypeNodePort
2016-04-27 04:35:14 +00:00
service . Spec . Ports [ 0 ] . NodePort = int32 ( outOfRangeNodePort )
2015-05-22 23:01:35 +00:00
service , err = t . CreateService ( service )
if err == nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "failed to prevent create of service with out-of-range NodePort (%d): %v" , outOfRangeNodePort , service )
2015-05-22 23:01:35 +00:00
}
2016-01-20 05:13:39 +00:00
Expect ( fmt . Sprintf ( "%v" , err ) ) . To ( MatchRegexp ( expectedErr ) )
2015-05-22 23:01:35 +00:00
} )
It ( "should release NodePorts on delete" , func ( ) {
2016-01-30 04:35:32 +00:00
// TODO: use the ServiceTestJig here
2015-05-22 23:01:35 +00:00
serviceName := "nodeport-reuse"
2015-09-29 21:30:45 +00:00
ns := f . Namespace . Name
2015-05-22 23:01:35 +00:00
2016-10-18 13:00:38 +00:00
t := NewServerTest ( cs , ns , serviceName )
2015-05-22 23:01:35 +00:00
defer func ( ) {
defer GinkgoRecover ( )
errs := t . Cleanup ( )
if len ( errs ) != 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "errors in cleanup: %v" , errs )
2015-05-22 23:01:35 +00:00
}
} ( )
service := t . BuildServiceSpec ( )
2016-11-18 20:55:17 +00:00
service . Spec . Type = v1 . ServiceTypeNodePort
2015-05-22 23:01:35 +00:00
By ( "creating service " + serviceName + " with type NodePort in namespace " + ns )
service , err := t . CreateService ( service )
2015-05-20 15:59:34 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2015-05-22 23:01:35 +00:00
2016-11-18 20:55:17 +00:00
if service . Spec . Type != v1 . ServiceTypeNodePort {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected Spec.Type for new service: %v" , service )
2015-05-22 23:01:35 +00:00
}
if len ( service . Spec . Ports ) != 1 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected len(Spec.Ports) for new service: %v" , service )
2015-05-20 15:59:34 +00:00
}
2015-05-22 23:01:35 +00:00
port := service . Spec . Ports [ 0 ]
if port . NodePort == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected Spec.Ports[0].nodePort for new service: %v" , service )
2015-05-20 15:59:34 +00:00
}
2016-04-27 04:35:14 +00:00
if ! ServiceNodePortRange . Contains ( int ( port . NodePort ) ) {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected (out-of-range) port for new service: %v" , service )
2015-05-22 23:01:35 +00:00
}
2015-06-17 22:26:14 +00:00
nodePort := port . NodePort
2015-05-22 23:01:35 +00:00
By ( "deleting original service " + serviceName )
err = t . DeleteService ( serviceName )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-10-18 13:00:38 +00:00
hostExec := framework . LaunchHostExecPod ( f . ClientSet , f . Namespace . Name , "hostexec" )
2015-11-12 23:30:21 +00:00
cmd := fmt . Sprintf ( ` ! ss -ant46 'sport = :%d' | tail -n +2 | grep LISTEN ` , nodePort )
2016-02-02 19:34:36 +00:00
var stdout string
2016-04-07 17:21:31 +00:00
if pollErr := wait . PollImmediate ( framework . Poll , kubeProxyLagTimeout , func ( ) ( bool , error ) {
2016-02-02 19:34:36 +00:00
var err error
2016-04-07 17:21:31 +00:00
stdout , err = framework . RunHostCmd ( hostExec . Namespace , hostExec . Name , cmd )
2016-02-02 19:34:36 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Logf ( "expected node port (%d) to not be in use, stdout: %v" , nodePort , stdout )
2016-02-02 19:34:36 +00:00
return false , nil
}
return true , nil
} ) ; pollErr != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "expected node port (%d) to not be in use in %v, stdout: %v" , nodePort , kubeProxyLagTimeout , stdout )
2015-06-17 22:26:14 +00:00
}
By ( fmt . Sprintf ( "creating service " + serviceName + " with same NodePort %d" , nodePort ) )
2015-05-22 23:01:35 +00:00
service = t . BuildServiceSpec ( )
2016-11-18 20:55:17 +00:00
service . Spec . Type = v1 . ServiceTypeNodePort
2015-06-17 22:26:14 +00:00
service . Spec . Ports [ 0 ] . NodePort = nodePort
2015-05-22 23:01:35 +00:00
service , err = t . CreateService ( service )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2015-05-20 15:59:34 +00:00
} )
2016-05-06 20:15:49 +00:00
It ( "should create endpoints for unready pods" , func ( ) {
serviceName := "never-ready"
ns := f . Namespace . Name
2016-10-18 13:00:38 +00:00
t := NewServerTest ( cs , ns , serviceName )
2016-05-06 20:15:49 +00:00
defer func ( ) {
defer GinkgoRecover ( )
errs := t . Cleanup ( )
if len ( errs ) != 0 {
framework . Failf ( "errors in cleanup: %v" , errs )
}
} ( )
service := t . BuildServiceSpec ( )
service . Annotations = map [ string ] string { endpoint . TolerateUnreadyEndpointsAnnotation : "true" }
2016-11-18 20:55:17 +00:00
rcSpec := rcByNameContainer ( t . name , 1 , t . image , t . Labels , v1 . Container {
2016-05-06 20:15:49 +00:00
Name : t . name ,
Image : t . image ,
2016-11-18 20:55:17 +00:00
Ports : [ ] v1 . ContainerPort { { ContainerPort : int32 ( 80 ) , Protocol : v1 . ProtocolTCP } } ,
ReadinessProbe : & v1 . Probe {
Handler : v1 . Handler {
Exec : & v1 . ExecAction {
2016-05-06 20:15:49 +00:00
Command : [ ] string { "/bin/false" } ,
} ,
} ,
} ,
2016-11-01 00:26:04 +00:00
} , nil )
2016-05-06 20:15:49 +00:00
By ( fmt . Sprintf ( "createing RC %v with selectors %v" , rcSpec . Name , rcSpec . Spec . Selector ) )
_ , err := t . createRC ( rcSpec )
ExpectNoError ( err )
By ( fmt . Sprintf ( "creating Service %v with selectors %v" , service . Name , service . Spec . Selector ) )
_ , err = t . CreateService ( service )
ExpectNoError ( err )
By ( "Verifying pods for RC " + t . name )
ExpectNoError ( framework . VerifyPods ( t . Client , t . Namespace , t . name , false , 1 ) )
svcName := fmt . Sprintf ( "%v.%v" , serviceName , f . Namespace . Name )
By ( "waiting for endpoints of Service with DNS name " + svcName )
2016-10-18 13:00:38 +00:00
execPodName := createExecPodOrFail ( f . ClientSet , f . Namespace . Name , "execpod-" )
2016-05-06 20:15:49 +00:00
cmd := fmt . Sprintf ( "wget -qO- %v" , svcName )
var stdout string
if pollErr := wait . PollImmediate ( framework . Poll , kubeProxyLagTimeout , func ( ) ( bool , error ) {
var err error
2016-06-15 11:14:05 +00:00
stdout , err = framework . RunHostCmd ( f . Namespace . Name , execPodName , cmd )
2016-05-06 20:15:49 +00:00
if err != nil {
framework . Logf ( "expected un-ready endpoint for Service %v, stdout: %v, err %v" , t . name , stdout , err )
return false , nil
}
return true , nil
} ) ; pollErr != nil {
framework . Failf ( "expected un-ready endpoint for Service %v within %v, stdout: %v" , t . name , kubeProxyLagTimeout , stdout )
}
} )
2016-09-15 00:00:00 +00:00
It ( "should only allow access from service loadbalancer source ranges [Slow]" , func ( ) {
// this feature currently supported only on GCE/GKE/AWS
framework . SkipUnlessProviderIs ( "gce" , "gke" , "aws" )
loadBalancerCreateTimeout := loadBalancerCreateTimeoutDefault
if nodes := framework . GetReadySchedulableNodesOrDie ( cs ) ; len ( nodes . Items ) > largeClusterMinNodesNumber {
loadBalancerCreateTimeout = loadBalancerCreateTimeoutLarge
}
namespace := f . Namespace . Name
serviceName := "lb-sourcerange"
jig := NewServiceTestJig ( cs , serviceName )
By ( "Prepare allow source ips" )
// prepare the exec pods
// acceptPod are allowed to access the loadbalancer
acceptPodName := createExecPodOrFail ( cs , namespace , "execpod-accept" )
dropPodName := createExecPodOrFail ( cs , namespace , "execpod-drop" )
accpetPod , err := cs . Core ( ) . Pods ( namespace ) . Get ( acceptPodName )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
dropPod , err := cs . Core ( ) . Pods ( namespace ) . Get ( dropPodName )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
By ( "creating a pod to be part of the service " + serviceName )
// This container is an nginx container listening on port 80
// See kubernetes/contrib/ingress/echoheaders/nginx.conf for content of response
jig . RunOrFail ( namespace , nil )
// Create loadbalancer service with source range from node[0] and podAccept
svc := jig . CreateTCPServiceOrFail ( namespace , func ( svc * v1 . Service ) {
svc . Spec . Type = v1 . ServiceTypeLoadBalancer
svc . Spec . LoadBalancerSourceRanges = [ ] string { accpetPod . Status . PodIP + "/32" }
} )
// Clean up loadbalancer service
defer func ( ) {
jig . UpdateServiceOrFail ( svc . Namespace , svc . Name , func ( svc * v1 . Service ) {
svc . Spec . Type = v1 . ServiceTypeNodePort
svc . Spec . LoadBalancerSourceRanges = nil
} )
Expect ( cs . Core ( ) . Services ( svc . Namespace ) . Delete ( svc . Name , nil ) ) . NotTo ( HaveOccurred ( ) )
} ( )
svc = jig . WaitForLoadBalancerOrFail ( namespace , serviceName , loadBalancerCreateTimeout )
jig . SanityCheckService ( svc , v1 . ServiceTypeLoadBalancer )
By ( "check reachability from different sources" )
svcIP := getIngressPoint ( & svc . Status . LoadBalancer . Ingress [ 0 ] )
checkReachabilityFromPod ( true , namespace , acceptPodName , svcIP )
checkReachabilityFromPod ( false , namespace , dropPodName , svcIP )
By ( "Update service LoadBalancerSourceRange and check reachability" )
jig . UpdateServiceOrFail ( svc . Namespace , svc . Name , func ( svc * v1 . Service ) {
// only allow access from dropPod
svc . Spec . LoadBalancerSourceRanges = [ ] string { dropPod . Status . PodIP + "/32" }
} )
checkReachabilityFromPod ( false , namespace , acceptPodName , svcIP )
checkReachabilityFromPod ( true , namespace , dropPodName , svcIP )
By ( "Delete LoadBalancerSourceRange field and check reachability" )
jig . UpdateServiceOrFail ( svc . Namespace , svc . Name , func ( svc * v1 . Service ) {
svc . Spec . LoadBalancerSourceRanges = nil
} )
checkReachabilityFromPod ( true , namespace , acceptPodName , svcIP )
checkReachabilityFromPod ( true , namespace , dropPodName , svcIP )
} )
2016-10-03 18:53:28 +00:00
} )
2016-12-05 23:35:55 +00:00
var _ = framework . KubeDescribe ( "ESIPP [Slow]" , func ( ) {
2016-10-03 18:53:28 +00:00
f := framework . NewDefaultFramework ( "esipp" )
loadBalancerCreateTimeout := loadBalancerCreateTimeoutDefault
var cs clientset . Interface
2016-09-07 02:48:04 +00:00
serviceLBNames := [ ] string { }
2016-08-22 17:48:00 +00:00
2016-10-03 18:53:28 +00:00
BeforeEach ( func ( ) {
2016-08-22 17:48:00 +00:00
// requires cloud load-balancer support - this feature currently supported only on GCE/GKE
framework . SkipUnlessProviderIs ( "gce" , "gke" )
2016-10-03 18:53:28 +00:00
cs = f . ClientSet
2016-10-19 01:43:13 +00:00
if nodes := framework . GetReadySchedulableNodesOrDie ( cs ) ; len ( nodes . Items ) > largeClusterMinNodesNumber {
2016-08-22 17:48:00 +00:00
loadBalancerCreateTimeout = loadBalancerCreateTimeoutLarge
}
2016-10-03 18:53:28 +00:00
} )
2016-09-07 02:48:04 +00:00
AfterEach ( func ( ) {
if CurrentGinkgoTestDescription ( ) . Failed {
describeSvc ( f . Namespace . Name )
}
for _ , lb := range serviceLBNames {
framework . Logf ( "cleaning gce resource for %s" , lb )
cleanupServiceGCEResources ( lb )
}
//reset serviceLBNames
serviceLBNames = [ ] string { }
} )
2016-12-05 23:35:55 +00:00
It ( "should work for type=LoadBalancer" , func ( ) {
2016-08-22 17:48:00 +00:00
namespace := f . Namespace . Name
serviceName := "external-local"
2016-10-18 13:00:38 +00:00
jig := NewServiceTestJig ( cs , serviceName )
2016-10-03 18:53:28 +00:00
svc := jig . createOnlyLocalLoadBalancerService ( namespace , serviceName , loadBalancerCreateTimeout , true )
2016-09-07 02:48:04 +00:00
serviceLBNames = append ( serviceLBNames , getLoadBalancerName ( svc ) )
2016-08-22 17:48:00 +00:00
healthCheckNodePort := int ( service . GetServiceHealthCheckNodePort ( svc ) )
if healthCheckNodePort == 0 {
framework . Failf ( "Service HealthCheck NodePort was not allocated" )
}
2016-10-03 18:53:28 +00:00
defer func ( ) {
2016-11-18 20:55:17 +00:00
jig . ChangeServiceType ( svc . Namespace , svc . Name , v1 . ServiceTypeClusterIP , loadBalancerCreateTimeout )
2016-10-03 18:53:28 +00:00
// Make sure we didn't leak the health check node port.
for name , ips := range jig . getEndpointNodes ( svc ) {
_ , fail , status := jig . TestHTTPHealthCheckNodePort ( ips [ 0 ] , healthCheckNodePort , "/healthz" , 5 )
if fail < 2 {
framework . Failf ( "Health check node port %v not released on node %v: %v" , healthCheckNodePort , name , status )
}
break
}
2016-10-18 13:00:38 +00:00
Expect ( cs . Core ( ) . Services ( svc . Namespace ) . Delete ( svc . Name , nil ) ) . NotTo ( HaveOccurred ( ) )
2016-10-03 18:53:28 +00:00
} ( )
svcTCPPort := int ( svc . Spec . Ports [ 0 ] . Port )
ingressIP := getIngressPoint ( & svc . Status . LoadBalancer . Ingress [ 0 ] )
2016-08-22 17:48:00 +00:00
By ( "reading clientIP using the TCP service's service port via its external VIP" )
2016-10-03 18:53:28 +00:00
content := jig . GetHTTPContent ( ingressIP , svcTCPPort , kubeProxyLagTimeout , "/clientip" )
2016-10-07 20:56:38 +00:00
clientIP := content . String ( )
2016-08-22 17:48:00 +00:00
framework . Logf ( "ClientIP detected by target pod using VIP:SvcPort is %s" , clientIP )
2016-10-03 18:53:28 +00:00
2016-08-22 17:48:00 +00:00
By ( "checking if Source IP is preserved" )
if strings . HasPrefix ( clientIP , "10." ) {
framework . Failf ( "Source IP was NOT preserved" )
}
2016-10-03 18:53:28 +00:00
} )
2016-12-05 23:35:55 +00:00
It ( "should work for type=NodePort" , func ( ) {
2016-10-03 18:53:28 +00:00
namespace := f . Namespace . Name
serviceName := "external-local"
2016-10-18 13:00:38 +00:00
jig := NewServiceTestJig ( cs , serviceName )
2016-10-03 18:53:28 +00:00
svc := jig . createOnlyLocalNodePortService ( namespace , serviceName , true )
defer func ( ) {
2016-10-18 13:00:38 +00:00
Expect ( cs . Core ( ) . Services ( svc . Namespace ) . Delete ( svc . Name , nil ) ) . NotTo ( HaveOccurred ( ) )
2016-10-03 18:53:28 +00:00
} ( )
tcpNodePort := int ( svc . Spec . Ports [ 0 ] . NodePort )
endpointsNodeMap := jig . getEndpointNodes ( svc )
path := "/clientip"
for nodeName , nodeIPs := range endpointsNodeMap {
nodeIP := nodeIPs [ 0 ]
By ( fmt . Sprintf ( "reading clientIP using the TCP service's NodePort, on node %v: %v%v%v" , nodeName , nodeIP , tcpNodePort , path ) )
content := jig . GetHTTPContent ( nodeIP , tcpNodePort , kubeProxyLagTimeout , path )
clientIP := content . String ( )
framework . Logf ( "ClientIP detected by target pod using NodePort is %s" , clientIP )
if strings . HasPrefix ( clientIP , "10." ) {
framework . Failf ( "Source IP was NOT preserved" )
}
2016-08-22 17:48:00 +00:00
}
2016-10-03 18:53:28 +00:00
} )
2016-12-05 23:35:55 +00:00
It ( "should only target nodes with endpoints [Feature:ExternalTrafficLocalOnly]" , func ( ) {
2016-10-03 18:53:28 +00:00
namespace := f . Namespace . Name
serviceName := "external-local"
2016-10-18 13:00:38 +00:00
jig := NewServiceTestJig ( cs , serviceName )
2016-10-03 18:53:28 +00:00
nodes := jig . getNodes ( maxNodesForEndpointsTests )
svc := jig . createOnlyLocalLoadBalancerService ( namespace , serviceName , loadBalancerCreateTimeout , false )
2016-09-07 02:48:04 +00:00
serviceLBNames = append ( serviceLBNames , getLoadBalancerName ( svc ) )
2016-10-03 18:53:28 +00:00
defer func ( ) {
2016-11-18 20:55:17 +00:00
jig . ChangeServiceType ( svc . Namespace , svc . Name , v1 . ServiceTypeClusterIP , loadBalancerCreateTimeout )
2016-10-18 13:00:38 +00:00
Expect ( cs . Core ( ) . Services ( svc . Namespace ) . Delete ( svc . Name , nil ) ) . NotTo ( HaveOccurred ( ) )
2016-10-03 18:53:28 +00:00
} ( )
healthCheckNodePort := int ( service . GetServiceHealthCheckNodePort ( svc ) )
if healthCheckNodePort == 0 {
framework . Failf ( "Service HealthCheck NodePort was not allocated" )
2016-08-22 17:48:00 +00:00
}
2016-10-03 18:53:28 +00:00
2016-11-18 20:55:17 +00:00
ips := collectAddresses ( nodes , v1 . NodeExternalIP )
2016-08-22 17:48:00 +00:00
if len ( ips ) == 0 {
2016-11-18 20:55:17 +00:00
ips = collectAddresses ( nodes , v1 . NodeLegacyHostIP )
2016-08-22 17:48:00 +00:00
}
2016-10-03 18:53:28 +00:00
ingressIP := getIngressPoint ( & svc . Status . LoadBalancer . Ingress [ 0 ] )
svcTCPPort := int ( svc . Spec . Ports [ 0 ] . Port )
threshold := 2
path := "/healthz"
for i := 0 ; i < len ( nodes . Items ) ; i ++ {
endpointNodeName := nodes . Items [ i ] . Name
By ( "creating a pod to be part of the service " + serviceName + " on node " + endpointNodeName )
2016-11-18 20:55:17 +00:00
jig . RunOrFail ( namespace , func ( rc * v1 . ReplicationController ) {
2016-10-03 18:53:28 +00:00
rc . Name = serviceName
if endpointNodeName != "" {
rc . Spec . Template . Spec . NodeName = endpointNodeName
}
} )
By ( fmt . Sprintf ( "waiting for service endpoint on node %v" , endpointNodeName ) )
jig . waitForEndpointOnNode ( namespace , serviceName , endpointNodeName )
2016-08-22 17:48:00 +00:00
// HealthCheck should pass only on the node where num(endpoints) > 0
// All other nodes should fail the healthcheck on the service healthCheckNodePort
2016-10-03 18:53:28 +00:00
for n , publicIP := range ips {
expectedSuccess := nodes . Items [ n ] . Name == endpointNodeName
framework . Logf ( "Health checking %s, http://%s:%d/%s, expectedSuccess %v" , nodes . Items [ n ] . Name , publicIP , healthCheckNodePort , path , expectedSuccess )
pass , fail , err := jig . TestHTTPHealthCheckNodePort ( publicIP , healthCheckNodePort , path , 5 )
if expectedSuccess && pass < threshold {
framework . Failf ( "Expected %s successes on %v/%v, got %d, err %v" , threshold , endpointNodeName , path , pass , err )
} else if ! expectedSuccess && fail < threshold {
framework . Failf ( "Expected %s failures on %v/%v, got %d, err %v" , threshold , endpointNodeName , path , fail , err )
}
// Make sure the loadbalancer picked up the helth check change
jig . TestReachableHTTP ( ingressIP , svcTCPPort , kubeProxyLagTimeout )
}
2016-11-18 20:55:17 +00:00
framework . ExpectNoError ( framework . DeleteRCAndPods ( f . ClientSet , f . InternalClientset , namespace , serviceName ) )
2016-10-03 18:53:28 +00:00
}
} )
2016-12-05 23:35:55 +00:00
It ( "should work from pods [Feature:ExternalTrafficLocalOnly]" , func ( ) {
2016-10-03 18:53:28 +00:00
namespace := f . Namespace . Name
serviceName := "external-local"
2016-10-18 13:00:38 +00:00
jig := NewServiceTestJig ( cs , serviceName )
2016-10-03 18:53:28 +00:00
nodes := jig . getNodes ( maxNodesForEndpointsTests )
svc := jig . createOnlyLocalLoadBalancerService ( namespace , serviceName , loadBalancerCreateTimeout , true )
2016-09-07 02:48:04 +00:00
serviceLBNames = append ( serviceLBNames , getLoadBalancerName ( svc ) )
2016-10-03 18:53:28 +00:00
defer func ( ) {
2016-11-18 20:55:17 +00:00
jig . ChangeServiceType ( svc . Namespace , svc . Name , v1 . ServiceTypeClusterIP , loadBalancerCreateTimeout )
2016-10-18 13:00:38 +00:00
Expect ( cs . Core ( ) . Services ( svc . Namespace ) . Delete ( svc . Name , nil ) ) . NotTo ( HaveOccurred ( ) )
2016-10-03 18:53:28 +00:00
} ( )
ingressIP := getIngressPoint ( & svc . Status . LoadBalancer . Ingress [ 0 ] )
path := fmt . Sprintf ( "%s:%d/clientip" , ingressIP , int ( svc . Spec . Ports [ 0 ] . Port ) )
nodeName := nodes . Items [ 0 ] . Name
podName := "execpod-sourceip"
By ( fmt . Sprintf ( "Creating %v on node %v" , podName , nodeName ) )
2016-10-18 13:00:38 +00:00
execPodName := createExecPodOnNode ( f . ClientSet , namespace , nodeName , podName )
2016-10-03 18:53:28 +00:00
defer func ( ) {
2016-10-18 13:00:38 +00:00
err := cs . Core ( ) . Pods ( namespace ) . Delete ( execPodName , nil )
2016-10-03 18:53:28 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
} ( )
2016-10-18 13:00:38 +00:00
execPod , err := f . ClientSet . Core ( ) . Pods ( namespace ) . Get ( execPodName )
2016-10-03 18:53:28 +00:00
ExpectNoError ( err )
framework . Logf ( "Waiting up to %v wget %v" , kubeProxyLagTimeout , path )
cmd := fmt . Sprintf ( ` wget -T 30 -qO- %v ` , path )
var srcIP string
By ( fmt . Sprintf ( "Hitting external lb %v from pod %v on node %v" , ingressIP , podName , nodeName ) )
if pollErr := wait . PollImmediate ( framework . Poll , loadBalancerCreateTimeoutDefault , func ( ) ( bool , error ) {
stdout , err := framework . RunHostCmd ( execPod . Namespace , execPod . Name , cmd )
if err != nil {
framework . Logf ( "got err: %v, retry until timeout" , err )
return false , nil
}
srcIP = strings . TrimSpace ( strings . Split ( stdout , ":" ) [ 0 ] )
return srcIP == execPod . Status . PodIP , nil
} ) ; pollErr != nil {
framework . Failf ( "Source IP not preserved from %v, expected '%v' got '%v'" , podName , execPod . Status . PodIP , srcIP )
}
} )
2016-12-05 23:35:55 +00:00
It ( "should handle updates to source ip annotation [Feature:ExternalTrafficLocalOnly]" , func ( ) {
2016-10-03 18:53:28 +00:00
namespace := f . Namespace . Name
serviceName := "external-local"
2016-10-18 13:00:38 +00:00
jig := NewServiceTestJig ( cs , serviceName )
2016-10-03 18:53:28 +00:00
nodes := jig . getNodes ( maxNodesForEndpointsTests )
if len ( nodes . Items ) < 2 {
framework . Failf ( "Need at least 2 nodes to verify source ip from a node without endpoint" )
}
svc := jig . createOnlyLocalLoadBalancerService ( namespace , serviceName , loadBalancerCreateTimeout , true )
2016-09-07 02:48:04 +00:00
serviceLBNames = append ( serviceLBNames , getLoadBalancerName ( svc ) )
2016-10-03 18:53:28 +00:00
defer func ( ) {
2016-11-18 20:55:17 +00:00
jig . ChangeServiceType ( svc . Namespace , svc . Name , v1 . ServiceTypeClusterIP , loadBalancerCreateTimeout )
2016-10-18 13:00:38 +00:00
Expect ( cs . Core ( ) . Services ( svc . Namespace ) . Delete ( svc . Name , nil ) ) . NotTo ( HaveOccurred ( ) )
2016-10-03 18:53:28 +00:00
} ( )
// save the health check node port because it disappears when lift the annotation.
healthCheckNodePort := int ( service . GetServiceHealthCheckNodePort ( svc ) )
By ( "turning ESIPP off" )
2016-11-18 20:55:17 +00:00
svc = jig . UpdateServiceOrFail ( svc . Namespace , svc . Name , func ( svc * v1 . Service ) {
2016-10-03 18:53:28 +00:00
svc . ObjectMeta . Annotations [ service . BetaAnnotationExternalTraffic ] =
service . AnnotationValueExternalTrafficGlobal
} )
if service . GetServiceHealthCheckNodePort ( svc ) > 0 {
framework . Failf ( "Service HealthCheck NodePort annotation still present" )
}
endpointNodeMap := jig . getEndpointNodes ( svc )
noEndpointNodeMap := map [ string ] [ ] string { }
for _ , n := range nodes . Items {
if _ , ok := endpointNodeMap [ n . Name ] ; ok {
continue
}
2016-11-18 20:55:17 +00:00
noEndpointNodeMap [ n . Name ] = getNodeAddresses ( & n , v1 . NodeExternalIP )
2016-10-03 18:53:28 +00:00
}
svcTCPPort := int ( svc . Spec . Ports [ 0 ] . Port )
svcNodePort := int ( svc . Spec . Ports [ 0 ] . NodePort )
ingressIP := getIngressPoint ( & svc . Status . LoadBalancer . Ingress [ 0 ] )
path := "/clientip"
By ( fmt . Sprintf ( "endpoints present on nodes %v, absent on nodes %v" , endpointNodeMap , noEndpointNodeMap ) )
for nodeName , nodeIPs := range noEndpointNodeMap {
2016-10-21 00:09:48 +00:00
By ( fmt . Sprintf ( "Checking %v (%v:%v%v) proxies to endpoints on another node" , nodeName , nodeIPs [ 0 ] , svcNodePort , path ) )
2016-10-03 18:53:28 +00:00
jig . GetHTTPContent ( nodeIPs [ 0 ] , svcNodePort , kubeProxyLagTimeout , path )
}
for nodeName , nodeIPs := range endpointNodeMap {
By ( fmt . Sprintf ( "checking kube-proxy health check fails on node with endpoint (%s), public IP %s" , nodeName , nodeIPs [ 0 ] ) )
var body bytes . Buffer
var result bool
var err error
if pollErr := wait . PollImmediate ( framework . Poll , timeout , func ( ) ( bool , error ) {
result , err = testReachableHTTPWithContent ( nodeIPs [ 0 ] , healthCheckNodePort , "/healthz" , "" , & body )
return ! result , nil
} ) ; pollErr != nil {
framework . Failf ( "Kube-proxy still exposing health check on node %v:%v, after ESIPP was turned off. Last err %v, last body %v" ,
nodeName , healthCheckNodePort , err , body . String ( ) )
}
}
// Poll till kube-proxy re-adds the MASQUERADE rule on the node.
By ( fmt . Sprintf ( "checking source ip is NOT preserved through loadbalancer %v" , ingressIP ) )
2016-10-21 00:09:48 +00:00
var clientIP string
2016-10-03 18:53:28 +00:00
pollErr := wait . PollImmediate ( framework . Poll , kubeProxyLagTimeout , func ( ) ( bool , error ) {
content := jig . GetHTTPContent ( ingressIP , svcTCPPort , kubeProxyLagTimeout , "/clientip" )
2016-10-21 00:09:48 +00:00
clientIP = content . String ( )
2016-10-03 18:53:28 +00:00
if strings . HasPrefix ( clientIP , "10." ) {
return true , nil
}
2016-10-21 00:09:48 +00:00
return false , nil
2016-10-03 18:53:28 +00:00
} )
if pollErr != nil {
2016-10-21 00:09:48 +00:00
framework . Failf ( "Source IP WAS preserved even after ESIPP turned off. Got %v, expected a ten-dot cluster ip." , clientIP )
2016-10-03 18:53:28 +00:00
}
// TODO: We need to attempt to create another service with the previously
// allocated healthcheck nodePort. If the health check nodePort has been
// freed, the new service creation will succeed, upon which we cleanup.
// If the health check nodePort has NOT been freed, the new service
// creation will fail.
By ( "turning ESIPP annotation back on" )
2016-11-18 20:55:17 +00:00
svc = jig . UpdateServiceOrFail ( svc . Namespace , svc . Name , func ( svc * v1 . Service ) {
2016-10-03 18:53:28 +00:00
svc . ObjectMeta . Annotations [ service . BetaAnnotationExternalTraffic ] =
service . AnnotationValueExternalTrafficLocal
// Request the same healthCheckNodePort as before, to test the user-requested allocation path
svc . ObjectMeta . Annotations [ service . BetaAnnotationHealthCheckNodePort ] =
fmt . Sprintf ( "%d" , healthCheckNodePort )
} )
pollErr = wait . PollImmediate ( framework . Poll , kubeProxyLagTimeout , func ( ) ( bool , error ) {
2016-10-21 00:09:48 +00:00
content := jig . GetHTTPContent ( ingressIP , svcTCPPort , kubeProxyLagTimeout , path )
clientIP = content . String ( )
By ( fmt . Sprintf ( "Endpoint %v:%v%v returned client ip %v" , ingressIP , svcTCPPort , path , clientIP ) )
2016-10-03 18:53:28 +00:00
if ! strings . HasPrefix ( clientIP , "10." ) {
return true , nil
}
2016-10-21 00:09:48 +00:00
return false , nil
2016-10-03 18:53:28 +00:00
} )
if pollErr != nil {
2016-10-21 00:09:48 +00:00
framework . Failf ( "Source IP (%v) is not the client IP even after ESIPP turned on, expected a public IP." , clientIP )
2016-08-22 17:48:00 +00:00
}
} )
2015-01-28 00:38:48 +00:00
} )
2015-02-09 20:37:56 +00:00
2015-07-10 20:38:37 +00:00
// updateService fetches a service, calls the update function on it,
// and then attempts to send the updated service. It retries up to 2
// times in the face of timeouts and conflicts.
2016-11-18 20:55:17 +00:00
func updateService ( c clientset . Interface , namespace , serviceName string , update func ( * v1 . Service ) ) ( * v1 . Service , error ) {
var service * v1 . Service
2015-07-10 20:38:37 +00:00
var err error
for i := 0 ; i < 3 ; i ++ {
2016-10-18 13:00:38 +00:00
service , err = c . Core ( ) . Services ( namespace ) . Get ( serviceName )
2015-07-10 20:38:37 +00:00
if err != nil {
return service , err
}
update ( service )
2016-10-18 13:00:38 +00:00
service , err = c . Core ( ) . Services ( namespace ) . Update ( service )
2015-07-10 20:38:37 +00:00
if ! errors . IsConflict ( err ) && ! errors . IsServerTimeout ( err ) {
return service , err
}
}
return service , err
}
2016-11-18 20:55:17 +00:00
func getContainerPortsByPodUID ( endpoints * v1 . Endpoints ) PortsByPodUID {
2015-06-26 08:08:48 +00:00
m := PortsByPodUID { }
2015-08-04 13:24:37 +00:00
for _ , ss := range endpoints . Subsets {
2015-03-20 21:24:43 +00:00
for _ , port := range ss . Ports {
2015-05-08 17:07:32 +00:00
for _ , addr := range ss . Addresses {
2015-08-04 13:24:37 +00:00
containerPort := port . Port
hostPort := port . Port
// use endpoint annotations to recover the container port in a Mesos setup
// compare contrib/mesos/pkg/service/endpoints_controller.syncService
2015-09-09 08:48:41 +00:00
key := fmt . Sprintf ( "k8s.mesosphere.io/containerPort_%s_%s_%d" , port . Protocol , addr . IP , hostPort )
mesosContainerPortString := endpoints . Annotations [ key ]
if mesosContainerPortString != "" {
2016-04-27 04:35:14 +00:00
mesosContainerPort , err := strconv . Atoi ( mesosContainerPortString )
2015-08-04 13:24:37 +00:00
if err != nil {
continue
}
2016-04-27 04:35:14 +00:00
containerPort = int32 ( mesosContainerPort )
2016-04-07 17:21:31 +00:00
framework . Logf ( "Mapped mesos host port %d to container port %d via annotation %s=%s" , hostPort , containerPort , key , mesosContainerPortString )
2015-08-04 13:24:37 +00:00
}
2016-04-07 17:21:31 +00:00
// framework.Logf("Found pod %v, host port %d and container port %d", addr.TargetRef.UID, hostPort, containerPort)
2015-06-26 08:08:48 +00:00
if _ , ok := m [ addr . TargetRef . UID ] ; ! ok {
m [ addr . TargetRef . UID ] = make ( [ ] int , 0 )
2015-03-20 21:24:43 +00:00
}
2016-04-27 04:35:14 +00:00
m [ addr . TargetRef . UID ] = append ( m [ addr . TargetRef . UID ] , int ( containerPort ) )
2015-03-20 21:24:43 +00:00
}
2015-02-09 20:37:56 +00:00
}
}
2015-05-08 17:07:32 +00:00
return m
2015-03-20 21:24:43 +00:00
}
2015-02-09 20:37:56 +00:00
2015-06-26 08:08:48 +00:00
type PortsByPodName map [ string ] [ ] int
type PortsByPodUID map [ types . UID ] [ ] int
2016-10-18 13:00:38 +00:00
func translatePodNameToUIDOrFail ( c clientset . Interface , ns string , expectedEndpoints PortsByPodName ) PortsByPodUID {
2015-06-26 08:08:48 +00:00
portsByUID := make ( PortsByPodUID )
2015-05-08 17:07:32 +00:00
for name , portList := range expectedEndpoints {
2016-10-18 13:00:38 +00:00
pod , err := c . Core ( ) . Pods ( ns ) . Get ( name )
2015-02-09 20:37:56 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "failed to get pod %s, that's pretty weird. validation failed: %s" , name , err )
2015-02-09 20:37:56 +00:00
}
2015-06-26 08:08:48 +00:00
portsByUID [ pod . ObjectMeta . UID ] = portList
2015-02-09 20:37:56 +00:00
}
2016-04-07 17:21:31 +00:00
// framework.Logf("successfully translated pod names to UIDs: %v -> %v on namespace %s", expectedEndpoints, portsByUID, ns)
2015-06-26 08:08:48 +00:00
return portsByUID
2015-05-08 17:07:32 +00:00
}
2015-06-26 08:08:48 +00:00
func validatePortsOrFail ( endpoints PortsByPodUID , expectedEndpoints PortsByPodUID ) {
2015-05-08 17:07:32 +00:00
if len ( endpoints ) != len ( expectedEndpoints ) {
// should not happen because we check this condition before
2016-04-07 17:21:31 +00:00
framework . Failf ( "invalid number of endpoints got %v, expected %v" , endpoints , expectedEndpoints )
2015-05-08 17:07:32 +00:00
}
2015-06-26 08:08:48 +00:00
for podUID := range expectedEndpoints {
if _ , ok := endpoints [ podUID ] ; ! ok {
2016-04-07 17:21:31 +00:00
framework . Failf ( "endpoint %v not found" , podUID )
2015-06-26 08:08:48 +00:00
}
if len ( endpoints [ podUID ] ) != len ( expectedEndpoints [ podUID ] ) {
2016-04-07 17:21:31 +00:00
framework . Failf ( "invalid list of ports for uid %v. Got %v, expected %v" , podUID , endpoints [ podUID ] , expectedEndpoints [ podUID ] )
2015-06-26 08:08:48 +00:00
}
sort . Ints ( endpoints [ podUID ] )
sort . Ints ( expectedEndpoints [ podUID ] )
for index := range endpoints [ podUID ] {
if endpoints [ podUID ] [ index ] != expectedEndpoints [ podUID ] [ index ] {
2016-04-07 17:21:31 +00:00
framework . Failf ( "invalid list of ports for uid %v. Got %v, expected %v" , podUID , endpoints [ podUID ] , expectedEndpoints [ podUID ] )
2015-05-08 17:07:32 +00:00
}
}
}
2015-02-09 20:37:56 +00:00
}
2016-10-18 13:00:38 +00:00
func validateEndpointsOrFail ( c clientset . Interface , namespace , serviceName string , expectedEndpoints PortsByPodName ) {
2016-04-07 17:21:31 +00:00
By ( fmt . Sprintf ( "waiting up to %v for service %s in namespace %s to expose endpoints %v" , framework . ServiceStartTimeout , serviceName , namespace , expectedEndpoints ) )
2015-09-29 21:30:45 +00:00
i := 1
2016-04-07 17:21:31 +00:00
for start := time . Now ( ) ; time . Since ( start ) < framework . ServiceStartTimeout ; time . Sleep ( 1 * time . Second ) {
2016-10-18 13:00:38 +00:00
endpoints , err := c . Core ( ) . Endpoints ( namespace ) . Get ( serviceName )
2015-07-01 21:58:37 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Get endpoints failed (%v elapsed, ignoring for 5s): %v" , time . Since ( start ) , err )
2015-07-01 21:58:37 +00:00
continue
}
2016-04-07 17:21:31 +00:00
// framework.Logf("Found endpoints %v", endpoints)
2015-05-08 17:07:32 +00:00
2015-08-04 13:24:37 +00:00
portsByPodUID := getContainerPortsByPodUID ( endpoints )
2016-04-07 17:21:31 +00:00
// framework.Logf("Found port by pod UID %v", portsByPodUID)
2015-05-08 17:07:32 +00:00
2015-06-26 08:08:48 +00:00
expectedPortsByPodUID := translatePodNameToUIDOrFail ( c , namespace , expectedEndpoints )
if len ( portsByPodUID ) == len ( expectedEndpoints ) {
validatePortsOrFail ( portsByPodUID , expectedPortsByPodUID )
2016-04-07 17:21:31 +00:00
framework . Logf ( "successfully validated that service %s in namespace %s exposes endpoints %v (%v elapsed)" ,
2015-09-29 21:30:45 +00:00
serviceName , namespace , expectedEndpoints , time . Since ( start ) )
2015-07-01 21:58:37 +00:00
return
2015-02-09 20:37:56 +00:00
}
2015-06-26 08:08:48 +00:00
2015-09-29 21:30:45 +00:00
if i % 5 == 0 {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Unexpected endpoints: found %v, expected %v (%v elapsed, will retry)" , portsByPodUID , expectedEndpoints , time . Since ( start ) )
2015-09-29 21:30:45 +00:00
}
i ++
2015-05-19 18:17:32 +00:00
}
2015-08-07 16:40:59 +00:00
2016-11-18 20:55:17 +00:00
if pods , err := c . Core ( ) . Pods ( v1 . NamespaceAll ) . List ( v1 . ListOptions { } ) ; err == nil {
2015-08-07 16:40:59 +00:00
for _ , pod := range pods . Items {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Pod %s\t%s\t%s\t%s" , pod . Namespace , pod . Name , pod . Spec . NodeName , pod . DeletionTimestamp )
2015-08-07 16:40:59 +00:00
}
} else {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Can't list pod debug info: %v" , err )
2015-08-07 16:40:59 +00:00
}
2016-04-07 17:21:31 +00:00
framework . Failf ( "Timed out waiting for service %s in namespace %s to expose endpoints %v (%v elapsed)" , serviceName , namespace , expectedEndpoints , framework . ServiceStartTimeout )
2015-02-09 20:37:56 +00:00
}
2016-08-17 04:07:17 +00:00
// newExecPodSpec returns the pod spec of exec pod
2016-11-18 20:55:17 +00:00
func newExecPodSpec ( ns , generateName string ) * v1 . Pod {
2015-12-14 20:26:23 +00:00
immediate := int64 ( 0 )
2016-11-18 20:55:17 +00:00
pod := & v1 . Pod {
ObjectMeta : v1 . ObjectMeta {
2016-06-15 11:14:05 +00:00
GenerateName : generateName ,
Namespace : ns ,
2015-12-14 20:26:23 +00:00
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . PodSpec {
2015-12-14 20:26:23 +00:00
TerminationGracePeriodSeconds : & immediate ,
2016-11-18 20:55:17 +00:00
Containers : [ ] v1 . Container {
2015-12-14 20:26:23 +00:00
{
Name : "exec" ,
2016-02-08 23:28:55 +00:00
Image : "gcr.io/google_containers/busybox:1.24" ,
2015-12-14 20:26:23 +00:00
Command : [ ] string { "sh" , "-c" , "while true; do sleep 5; done" } ,
} ,
} ,
} ,
}
2016-08-17 04:07:17 +00:00
return pod
}
// createExecPodOrFail creates a simple busybox pod in a sleep loop used as a
// vessel for kubectl exec commands.
// Returns the name of the created pod.
2016-10-18 13:00:38 +00:00
func createExecPodOrFail ( client clientset . Interface , ns , generateName string ) string {
2016-08-17 04:07:17 +00:00
framework . Logf ( "Creating new exec pod" )
execPod := newExecPodSpec ( ns , generateName )
2016-10-18 13:00:38 +00:00
created , err := client . Core ( ) . Pods ( ns ) . Create ( execPod )
2016-08-17 04:07:17 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
err = wait . PollImmediate ( framework . Poll , 5 * time . Minute , func ( ) ( bool , error ) {
2016-10-18 13:00:38 +00:00
retrievedPod , err := client . Core ( ) . Pods ( execPod . Namespace ) . Get ( created . Name )
2016-08-17 04:07:17 +00:00
if err != nil {
return false , nil
}
2016-11-18 20:55:17 +00:00
return retrievedPod . Status . Phase == v1 . PodRunning , nil
2016-08-17 04:07:17 +00:00
} )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
return created . Name
}
// createExecPodOnNode launches a exec pod in the given namespace and node
// waits until it's Running, created pod name would be returned
2016-10-18 13:00:38 +00:00
func createExecPodOnNode ( client clientset . Interface , ns , nodeName , generateName string ) string {
2016-08-17 04:07:17 +00:00
framework . Logf ( "Creating exec pod %q in namespace %q" , generateName , ns )
execPod := newExecPodSpec ( ns , generateName )
execPod . Spec . NodeName = nodeName
2016-10-18 13:00:38 +00:00
created , err := client . Core ( ) . Pods ( ns ) . Create ( execPod )
2015-12-14 20:26:23 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-04-07 17:21:31 +00:00
err = wait . PollImmediate ( framework . Poll , 5 * time . Minute , func ( ) ( bool , error ) {
2016-10-18 13:00:38 +00:00
retrievedPod , err := client . Core ( ) . Pods ( execPod . Namespace ) . Get ( created . Name )
2015-12-14 20:26:23 +00:00
if err != nil {
return false , nil
}
2016-11-18 20:55:17 +00:00
return retrievedPod . Status . Phase == v1 . PodRunning , nil
2015-12-14 20:26:23 +00:00
} )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2016-06-15 11:14:05 +00:00
return created . Name
2015-12-14 20:26:23 +00:00
}
2016-11-18 20:55:17 +00:00
func createPodOrFail ( c clientset . Interface , ns , name string , labels map [ string ] string , containerPorts [ ] v1 . ContainerPort ) {
2015-09-29 21:30:45 +00:00
By ( fmt . Sprintf ( "creating pod %s in namespace %s" , name , ns ) )
2016-11-18 20:55:17 +00:00
pod := & v1 . Pod {
ObjectMeta : v1 . ObjectMeta {
2015-02-09 20:37:56 +00:00
Name : name ,
Labels : labels ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2015-02-09 20:37:56 +00:00
{
2016-05-26 16:16:43 +00:00
Name : "pause" ,
Image : framework . GetPauseImageName ( c ) ,
2015-05-08 17:07:32 +00:00
Ports : containerPorts ,
2016-04-26 23:25:26 +00:00
// Add a dummy environment variable to work around a docker issue.
// https://github.com/docker/docker/issues/14203
2016-11-18 20:55:17 +00:00
Env : [ ] v1 . EnvVar { { Name : "FOO" , Value : " " } } ,
2015-02-09 20:37:56 +00:00
} ,
} ,
} ,
}
2016-10-18 13:00:38 +00:00
_ , err := c . Core ( ) . Pods ( ns ) . Create ( pod )
2015-02-09 20:37:56 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
2015-05-20 15:59:34 +00:00
2016-10-18 13:00:38 +00:00
func deletePodOrFail ( c clientset . Interface , ns , name string ) {
2015-09-29 21:30:45 +00:00
By ( fmt . Sprintf ( "deleting pod %s in namespace %s" , name , ns ) )
2016-10-18 13:00:38 +00:00
err := c . Core ( ) . Pods ( ns ) . Delete ( name , nil )
2015-09-29 21:30:45 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}
2016-11-18 20:55:17 +00:00
func getNodeAddresses ( node * v1 . Node , addressType v1 . NodeAddressType ) ( ips [ ] string ) {
2016-10-03 18:53:28 +00:00
for j := range node . Status . Addresses {
nodeAddress := & node . Status . Addresses [ j ]
if nodeAddress . Type == addressType {
ips = append ( ips , nodeAddress . Address )
}
}
return
}
2016-11-18 20:55:17 +00:00
func collectAddresses ( nodes * v1 . NodeList , addressType v1 . NodeAddressType ) [ ] string {
2015-05-20 15:59:34 +00:00
ips := [ ] string { }
for i := range nodes . Items {
2016-10-03 18:53:28 +00:00
ips = append ( ips , getNodeAddresses ( & nodes . Items [ i ] , addressType ) ... )
2015-05-20 15:59:34 +00:00
}
return ips
}
2016-10-18 13:00:38 +00:00
func getNodePublicIps ( c clientset . Interface ) ( [ ] string , error ) {
nodes := framework . GetReadySchedulableNodesOrDie ( c )
2015-05-20 15:59:34 +00:00
2016-11-18 20:55:17 +00:00
ips := collectAddresses ( nodes , v1 . NodeExternalIP )
2015-05-20 15:59:34 +00:00
if len ( ips ) == 0 {
2016-11-18 20:55:17 +00:00
ips = collectAddresses ( nodes , v1 . NodeLegacyHostIP )
2015-05-20 15:59:34 +00:00
}
return ips , nil
}
2015-05-22 23:01:35 +00:00
2016-10-18 13:00:38 +00:00
func pickNodeIP ( c clientset . Interface ) string {
publicIps , err := getNodePublicIps ( c )
2015-05-22 23:01:35 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
if len ( publicIps ) == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "got unexpected number (%d) of public IPs" , len ( publicIps ) )
2015-05-22 23:01:35 +00:00
}
ip := publicIps [ 0 ]
return ip
}
2016-01-30 04:35:32 +00:00
func testReachableHTTP ( ip string , port int , request string , expect string ) ( bool , error ) {
2016-08-22 17:48:00 +00:00
return testReachableHTTPWithContent ( ip , port , request , expect , nil )
}
func testReachableHTTPWithContent ( ip string , port int , request string , expect string , content * bytes . Buffer ) ( bool , error ) {
2016-01-30 04:35:32 +00:00
url := fmt . Sprintf ( "http://%s:%d%s" , ip , port , request )
2015-12-06 21:23:56 +00:00
if ip == "" {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Got empty IP for reachability check (%s)" , url )
2015-12-06 21:23:56 +00:00
return false , nil
}
if port == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Got port==0 for reachability check (%s)" , url )
2015-12-06 21:23:56 +00:00
return false , nil
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "Testing HTTP reachability of %v" , url )
2015-12-06 21:23:56 +00:00
resp , err := httpGetNoConnectionPool ( url )
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Got error testing for reachability of %s: %v" , url , err )
2015-12-06 21:23:56 +00:00
return false , nil
}
defer resp . Body . Close ( )
body , err := ioutil . ReadAll ( resp . Body )
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Got error reading response from %s: %v" , url , err )
2015-12-06 21:23:56 +00:00
return false , nil
}
if resp . StatusCode != 200 {
2016-08-22 17:48:00 +00:00
return false , fmt . Errorf ( "received non-success return status %q trying to access %s; got body: %s" ,
resp . Status , url , string ( body ) )
2015-12-06 21:23:56 +00:00
}
2016-01-30 04:35:32 +00:00
if ! strings . Contains ( string ( body ) , expect ) {
return false , fmt . Errorf ( "received response body without expected substring %q: %s" , expect , string ( body ) )
2015-12-06 21:23:56 +00:00
}
2016-08-22 17:48:00 +00:00
if content != nil {
content . Write ( body )
}
2015-12-06 21:23:56 +00:00
return true , nil
2015-09-29 21:30:45 +00:00
}
2016-08-22 17:48:00 +00:00
func testHTTPHealthCheckNodePort ( ip string , port int , request string ) ( bool , error ) {
url := fmt . Sprintf ( "http://%s:%d%s" , ip , port , request )
if ip == "" || port == 0 {
framework . Failf ( "Got empty IP for reachability check (%s)" , url )
return false , fmt . Errorf ( "Invalid input ip or port" )
}
framework . Logf ( "Testing HTTP health check on %v" , url )
resp , err := httpGetNoConnectionPool ( url )
if err != nil {
framework . Logf ( "Got error testing for reachability of %s: %v" , url , err )
return false , err
}
defer resp . Body . Close ( )
if err != nil {
framework . Logf ( "Got error reading response from %s: %v" , url , err )
return false , err
}
// HealthCheck responder returns 503 for no local endpoints
if resp . StatusCode == 503 {
return false , nil
}
// HealthCheck responder returns 200 for non-zero local endpoints
if resp . StatusCode == 200 {
return true , nil
}
return false , fmt . Errorf ( "Unexpected HTTP response code %s from health check responder at %s" , resp . Status , url )
}
2016-01-30 04:35:32 +00:00
func testNotReachableHTTP ( ip string , port int ) ( bool , error ) {
url := fmt . Sprintf ( "http://%s:%d" , ip , port )
if ip == "" {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Got empty IP for non-reachability check (%s)" , url )
2016-01-30 04:35:32 +00:00
return false , nil
}
if port == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Got port==0 for non-reachability check (%s)" , url )
2016-01-30 04:35:32 +00:00
return false , nil
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "Testing HTTP non-reachability of %v" , url )
2016-01-30 04:35:32 +00:00
resp , err := httpGetNoConnectionPool ( url )
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Confirmed that %s is not reachable" , url )
2016-01-30 04:35:32 +00:00
return true , nil
}
resp . Body . Close ( )
return false , nil
}
func testReachableUDP ( ip string , port int , request string , expect string ) ( bool , error ) {
2015-12-06 21:23:56 +00:00
uri := fmt . Sprintf ( "udp://%s:%d" , ip , port )
if ip == "" {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Got empty IP for reachability check (%s)" , uri )
2015-12-06 21:23:56 +00:00
return false , nil
}
if port == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Got port==0 for reachability check (%s)" , uri )
2015-12-06 21:23:56 +00:00
return false , nil
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "Testing UDP reachability of %v" , uri )
2015-12-06 21:23:56 +00:00
2016-01-30 04:35:32 +00:00
con , err := net . Dial ( "udp" , ip + ":" + strconv . Itoa ( port ) )
2015-09-28 20:57:58 +00:00
if err != nil {
2016-01-30 04:35:32 +00:00
return false , fmt . Errorf ( "Failed to dial %s:%d: %v" , ip , port , err )
2015-09-28 20:57:58 +00:00
}
2016-01-30 04:35:32 +00:00
_ , err = con . Write ( [ ] byte ( fmt . Sprintf ( "%s\n" , request ) ) )
2015-09-28 20:57:58 +00:00
if err != nil {
2016-01-30 04:35:32 +00:00
return false , fmt . Errorf ( "Failed to send request: %v" , err )
2015-09-28 20:57:58 +00:00
}
2016-01-30 04:35:32 +00:00
var buf [ ] byte = make ( [ ] byte , len ( expect ) + 1 )
err = con . SetDeadline ( time . Now ( ) . Add ( 3 * time . Second ) )
if err != nil {
return false , fmt . Errorf ( "Failed to set deadline: %v" , err )
}
2015-09-28 20:57:58 +00:00
_ , err = con . Read ( buf )
if err != nil {
2016-01-30 04:35:32 +00:00
return false , nil
2015-09-28 20:57:58 +00:00
}
2016-01-30 04:35:32 +00:00
if ! strings . Contains ( string ( buf ) , expect ) {
return false , fmt . Errorf ( "Failed to retrieve %q, got %q" , expect , string ( buf ) )
2015-09-28 20:57:58 +00:00
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "Successfully reached %v" , uri )
2015-12-06 21:23:56 +00:00
return true , nil
2015-09-28 20:57:58 +00:00
}
2016-01-30 04:35:32 +00:00
func testNotReachableUDP ( ip string , port int , request string ) ( bool , error ) {
uri := fmt . Sprintf ( "udp://%s:%d" , ip , port )
if ip == "" {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Got empty IP for reachability check (%s)" , uri )
2016-01-30 04:35:32 +00:00
return false , nil
}
if port == 0 {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Got port==0 for reachability check (%s)" , uri )
2016-01-30 04:35:32 +00:00
return false , nil
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "Testing UDP non-reachability of %v" , uri )
2016-01-30 04:35:32 +00:00
con , err := net . Dial ( "udp" , ip + ":" + strconv . Itoa ( port ) )
2015-09-29 21:30:45 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Confirmed that %s is not reachable" , uri )
2016-01-30 04:35:32 +00:00
return true , nil
2015-09-29 21:30:45 +00:00
}
2015-05-22 23:01:35 +00:00
2016-01-30 04:35:32 +00:00
_ , err = con . Write ( [ ] byte ( fmt . Sprintf ( "%s\n" , request ) ) )
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Confirmed that %s is not reachable" , uri )
2016-01-30 04:35:32 +00:00
return true , nil
2015-05-22 23:01:35 +00:00
}
2016-01-30 04:35:32 +00:00
var buf [ ] byte = make ( [ ] byte , 1 )
err = con . SetDeadline ( time . Now ( ) . Add ( 3 * time . Second ) )
if err != nil {
return false , fmt . Errorf ( "Failed to set deadline: %v" , err )
2015-05-22 23:01:35 +00:00
}
2016-01-30 04:35:32 +00:00
_ , err = con . Read ( buf )
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Confirmed that %s is not reachable" , uri )
2016-01-30 04:35:32 +00:00
return true , nil
}
return false , nil
2015-05-22 23:01:35 +00:00
}
2015-07-16 12:38:47 +00:00
// Creates a replication controller that serves its hostname and a service on top of it.
2016-11-18 20:55:17 +00:00
func startServeHostnameService ( c clientset . Interface , internalClient internalclientset . Interface , ns , name string , port , replicas int ) ( [ ] string , string , error ) {
2015-07-16 12:38:47 +00:00
podNames := make ( [ ] string , replicas )
2015-09-29 21:30:45 +00:00
By ( "creating service " + name + " in namespace " + ns )
2016-11-18 20:55:17 +00:00
_ , err := c . Core ( ) . Services ( ns ) . Create ( & v1 . Service {
ObjectMeta : v1 . ObjectMeta {
2015-07-16 12:38:47 +00:00
Name : name ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . ServiceSpec {
Ports : [ ] v1 . ServicePort { {
2016-04-27 04:35:14 +00:00
Port : int32 ( port ) ,
2015-11-10 06:28:45 +00:00
TargetPort : intstr . FromInt ( 9376 ) ,
2015-07-16 12:38:47 +00:00
Protocol : "TCP" ,
} } ,
Selector : map [ string ] string {
"name" : name ,
} ,
} ,
} )
if err != nil {
return podNames , "" , err
}
2016-11-18 20:55:17 +00:00
var createdPods [ ] * v1 . Pod
2015-07-16 12:38:47 +00:00
maxContainerFailures := 0
2016-10-12 11:37:37 +00:00
config := testutils . RCConfig {
2015-07-16 12:38:47 +00:00
Client : c ,
2016-11-18 20:55:17 +00:00
InternalClient : internalClient ,
2016-03-21 19:53:22 +00:00
Image : "gcr.io/google_containers/serve_hostname:v1.4" ,
2015-07-16 12:38:47 +00:00
Name : name ,
Namespace : ns ,
PollInterval : 3 * time . Second ,
2016-04-07 17:21:31 +00:00
Timeout : framework . PodReadyBeforeTimeout ,
2015-07-16 12:38:47 +00:00
Replicas : replicas ,
CreatedPods : & createdPods ,
MaxContainerFailures : & maxContainerFailures ,
}
2016-04-07 17:21:31 +00:00
err = framework . RunRC ( config )
2015-07-16 12:38:47 +00:00
if err != nil {
return podNames , "" , err
}
if len ( createdPods ) != replicas {
return podNames , "" , fmt . Errorf ( "Incorrect number of running pods: %v" , len ( createdPods ) )
}
for i := range createdPods {
podNames [ i ] = createdPods [ i ] . ObjectMeta . Name
}
sort . StringSlice ( podNames ) . Sort ( )
2016-10-18 13:00:38 +00:00
service , err := c . Core ( ) . Services ( ns ) . Get ( name )
2015-07-16 12:38:47 +00:00
if err != nil {
return podNames , "" , err
}
if service . Spec . ClusterIP == "" {
return podNames , "" , fmt . Errorf ( "Service IP is blank for %v" , name )
}
serviceIP := service . Spec . ClusterIP
return podNames , serviceIP , nil
}
2016-11-18 20:55:17 +00:00
func stopServeHostnameService ( clientset clientset . Interface , internalClientset internalclientset . Interface , ns , name string ) error {
if err := framework . DeleteRCAndPods ( clientset , internalClientset , ns , name ) ; err != nil {
2015-07-16 12:38:47 +00:00
return err
}
2016-10-18 13:00:38 +00:00
if err := clientset . Core ( ) . Services ( ns ) . Delete ( name , nil ) ; err != nil {
2015-07-16 12:38:47 +00:00
return err
}
return nil
}
2015-12-14 20:26:23 +00:00
// verifyServeHostnameServiceUp wgets the given serviceIP:servicePort from the
// given host and from within a pod. The host is expected to be an SSH-able node
// in the cluster. Each pod in the service is expected to echo its name. These
// names are compared with the given expectedPods list after a sort | uniq.
2016-10-18 13:00:38 +00:00
func verifyServeHostnameServiceUp ( c clientset . Interface , ns , host string , expectedPods [ ] string , serviceIP string , servicePort int ) error {
2016-06-15 11:14:05 +00:00
execPodName := createExecPodOrFail ( c , ns , "execpod-" )
2015-12-14 20:26:23 +00:00
defer func ( ) {
deletePodOrFail ( c , ns , execPodName )
} ( )
2016-02-03 19:06:08 +00:00
2015-12-23 06:46:52 +00:00
// Loop a bunch of times - the proxy is randomized, so we want a good
// chance of hitting each backend at least once.
2016-02-03 19:06:08 +00:00
buildCommand := func ( wget string ) string {
return fmt . Sprintf ( "for i in $(seq 1 %d); do %s http://%s:%d 2>&1 || true; echo; done" ,
50 * len ( expectedPods ) , wget , serviceIP , servicePort )
}
2015-12-14 20:26:23 +00:00
commands := [ ] func ( ) string {
2015-07-16 12:38:47 +00:00
// verify service from node
2015-12-14 20:26:23 +00:00
func ( ) string {
2016-02-03 19:06:08 +00:00
cmd := "set -e; " + buildCommand ( "wget -q --timeout=0.2 --tries=1 -O -" )
2016-04-07 17:21:31 +00:00
framework . Logf ( "Executing cmd %q on host %v" , cmd , host )
result , err := framework . SSH ( cmd , host , framework . TestContext . Provider )
2015-11-20 21:54:34 +00:00
if err != nil || result . Code != 0 {
2016-04-07 17:21:31 +00:00
framework . LogSSHResult ( result )
framework . Logf ( "error while SSH-ing to node: %v" , err )
2015-07-16 12:38:47 +00:00
}
2015-12-14 20:26:23 +00:00
return result . Stdout
} ,
// verify service from pod
func ( ) string {
2016-02-03 19:06:08 +00:00
cmd := buildCommand ( "wget -q -T 1 -O -" )
2016-04-07 17:21:31 +00:00
framework . Logf ( "Executing cmd %q in pod %v/%v" , cmd , ns , execPodName )
2015-12-14 20:26:23 +00:00
// TODO: Use exec-over-http via the netexec pod instead of kubectl exec.
2016-04-07 17:21:31 +00:00
output , err := framework . RunHostCmd ( ns , execPodName , cmd )
2015-12-14 20:26:23 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Logf ( "error while kubectl execing %q in pod %v/%v: %v\nOutput: %v" , cmd , ns , execPodName , err , output )
2015-12-14 20:26:23 +00:00
}
return output
} ,
}
2016-02-25 21:09:17 +00:00
expectedEndpoints := sets . NewString ( expectedPods ... )
2015-12-14 20:26:23 +00:00
By ( fmt . Sprintf ( "verifying service has %d reachable backends" , len ( expectedPods ) ) )
for _ , cmdFunc := range commands {
passed := false
2016-02-25 21:09:17 +00:00
gotEndpoints := sets . NewString ( )
2015-12-23 06:46:52 +00:00
// Retry cmdFunc for a while
2016-02-25 21:09:17 +00:00
for start := time . Now ( ) ; time . Since ( start ) < kubeProxyLagTimeout ; time . Sleep ( 5 * time . Second ) {
for _ , endpoint := range strings . Split ( cmdFunc ( ) , "\n" ) {
trimmedEp := strings . TrimSpace ( endpoint )
if trimmedEp != "" {
gotEndpoints . Insert ( trimmedEp )
}
}
2016-02-29 21:10:48 +00:00
// TODO: simply checking that the retrieved endpoints is a superset
// of the expected allows us to ignore intermitten network flakes that
// result in output like "wget timed out", but these should be rare
// and we need a better way to track how often it occurs.
if gotEndpoints . IsSuperset ( expectedEndpoints ) {
if ! gotEndpoints . Equal ( expectedEndpoints ) {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Ignoring unexpected output wgetting endpoints of service %s: %v" , serviceIP , gotEndpoints . Difference ( expectedEndpoints ) )
2016-02-29 21:10:48 +00:00
}
2015-07-16 12:38:47 +00:00
passed = true
break
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "Unable to reach the following endpoints of service %s: %v" , serviceIP , expectedEndpoints . Difference ( gotEndpoints ) )
2015-07-16 12:38:47 +00:00
}
if ! passed {
2016-02-25 21:09:17 +00:00
// Sort the lists so they're easier to visually diff.
exp := expectedEndpoints . List ( )
got := gotEndpoints . List ( )
sort . StringSlice ( exp ) . Sort ( )
sort . StringSlice ( got ) . Sort ( )
return fmt . Errorf ( "service verification failed for: %s\nexpected %v\nreceived %v" , serviceIP , exp , got )
2015-07-16 12:38:47 +00:00
}
}
return nil
}
2016-10-18 13:00:38 +00:00
func verifyServeHostnameServiceDown ( c clientset . Interface , host string , serviceIP string , servicePort int ) error {
2015-07-16 12:38:47 +00:00
command := fmt . Sprintf (
"curl -s --connect-timeout 2 http://%s:%d && exit 99" , serviceIP , servicePort )
for start := time . Now ( ) ; time . Since ( start ) < time . Minute ; time . Sleep ( 5 * time . Second ) {
2016-04-07 17:21:31 +00:00
result , err := framework . SSH ( command , host , framework . TestContext . Provider )
2015-07-16 12:38:47 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . LogSSHResult ( result )
framework . Logf ( "error while SSH-ing to node: %v" , err )
2015-07-16 12:38:47 +00:00
}
2015-11-20 21:54:34 +00:00
if result . Code != 99 {
2015-07-16 12:38:47 +00:00
return nil
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "service still alive - still waiting" )
2015-07-16 12:38:47 +00:00
}
return fmt . Errorf ( "waiting for service to be down timed out" )
}
2015-05-22 23:01:35 +00:00
// Does an HTTP GET, but does not reuse TCP connections
// This masks problems where the iptables rule has changed, but we don't see it
2015-05-23 12:20:49 +00:00
// This is intended for relatively quick requests (status checks), so we set a short (5 seconds) timeout
2015-05-22 23:01:35 +00:00
func httpGetNoConnectionPool ( url string ) ( * http . Response , error ) {
2016-03-15 19:29:08 +00:00
tr := utilnet . SetTransportDefaults ( & http . Transport {
2015-05-22 23:01:35 +00:00
DisableKeepAlives : true ,
2016-03-15 19:29:08 +00:00
} )
2015-05-22 23:01:35 +00:00
client := & http . Client {
Transport : tr ,
2015-05-23 12:20:49 +00:00
Timeout : 5 * time . Second ,
2015-05-22 23:01:35 +00:00
}
return client . Get ( url )
}
2016-01-30 04:35:32 +00:00
// A test jig to help testing.
type ServiceTestJig struct {
2016-10-18 13:00:38 +00:00
ID string
Name string
Client clientset . Interface
Labels map [ string ] string
2016-01-30 04:35:32 +00:00
}
// NewServiceTestJig allocates and inits a new ServiceTestJig.
2016-10-18 13:00:38 +00:00
func NewServiceTestJig ( client clientset . Interface , name string ) * ServiceTestJig {
2016-01-30 04:35:32 +00:00
j := & ServiceTestJig { }
j . Client = client
j . Name = name
2016-07-26 15:13:18 +00:00
j . ID = j . Name + "-" + string ( uuid . NewUUID ( ) )
2016-01-30 04:35:32 +00:00
j . Labels = map [ string ] string { "testid" : j . ID }
return j
}
2016-11-18 20:55:17 +00:00
// newServiceTemplate returns the default v1.Service template for this jig, but
2016-01-30 04:35:32 +00:00
// does not actually create the Service. The default Service has the same name
2016-08-17 04:07:17 +00:00
// as the jig and exposes the given port.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) newServiceTemplate ( namespace string , proto v1 . Protocol , port int32 ) * v1 . Service {
service := & v1 . Service {
ObjectMeta : v1 . ObjectMeta {
2016-01-30 04:35:32 +00:00
Namespace : namespace ,
Name : j . Name ,
Labels : j . Labels ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . ServiceSpec {
2016-01-30 04:35:32 +00:00
Selector : j . Labels ,
2016-11-18 20:55:17 +00:00
Ports : [ ] v1 . ServicePort {
2016-01-30 04:35:32 +00:00
{
Protocol : proto ,
2016-08-17 04:07:17 +00:00
Port : port ,
2016-01-30 04:35:32 +00:00
} ,
} ,
} ,
}
return service
}
2016-08-17 04:07:17 +00:00
// CreateTCPServiceWithPort creates a new TCP Service with given port based on the
// jig's defaults. Callers can provide a function to tweak the Service object before
// it is created.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) CreateTCPServiceWithPort ( namespace string , tweak func ( svc * v1 . Service ) , port int32 ) * v1 . Service {
svc := j . newServiceTemplate ( namespace , v1 . ProtocolTCP , port )
2016-08-17 04:07:17 +00:00
if tweak != nil {
tweak ( svc )
}
2016-10-18 13:00:38 +00:00
result , err := j . Client . Core ( ) . Services ( namespace ) . Create ( svc )
2016-08-17 04:07:17 +00:00
if err != nil {
framework . Failf ( "Failed to create TCP Service %q: %v" , svc . Name , err )
}
return result
}
2016-01-30 04:35:32 +00:00
// CreateTCPServiceOrFail creates a new TCP Service based on the jig's
// defaults. Callers can provide a function to tweak the Service object before
// it is created.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) CreateTCPServiceOrFail ( namespace string , tweak func ( svc * v1 . Service ) ) * v1 . Service {
svc := j . newServiceTemplate ( namespace , v1 . ProtocolTCP , 80 )
2016-01-30 04:35:32 +00:00
if tweak != nil {
tweak ( svc )
}
2016-10-18 13:00:38 +00:00
result , err := j . Client . Core ( ) . Services ( namespace ) . Create ( svc )
2016-01-30 04:35:32 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Failed to create TCP Service %q: %v" , svc . Name , err )
2016-01-30 04:35:32 +00:00
}
return result
}
// CreateUDPServiceOrFail creates a new UDP Service based on the jig's
// defaults. Callers can provide a function to tweak the Service object before
// it is created.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) CreateUDPServiceOrFail ( namespace string , tweak func ( svc * v1 . Service ) ) * v1 . Service {
svc := j . newServiceTemplate ( namespace , v1 . ProtocolUDP , 80 )
2016-01-30 04:35:32 +00:00
if tweak != nil {
tweak ( svc )
}
2016-10-18 13:00:38 +00:00
result , err := j . Client . Core ( ) . Services ( namespace ) . Create ( svc )
2016-01-30 04:35:32 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Failed to create UDP Service %q: %v" , svc . Name , err )
2016-01-30 04:35:32 +00:00
}
return result
}
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) ChangeServiceType ( namespace , name string , newType v1 . ServiceType , timeout time . Duration ) {
2016-10-03 18:53:28 +00:00
ingressIP := ""
2016-11-18 20:55:17 +00:00
svc := j . UpdateServiceOrFail ( namespace , name , func ( s * v1 . Service ) {
2016-10-03 18:53:28 +00:00
for _ , ing := range s . Status . LoadBalancer . Ingress {
if ing . IP != "" {
ingressIP = ing . IP
}
}
s . Spec . Type = newType
s . Spec . Ports [ 0 ] . NodePort = 0
} )
if ingressIP != "" {
j . WaitForLoadBalancerDestroyOrFail ( namespace , svc . Name , ingressIP , int ( svc . Spec . Ports [ 0 ] . Port ) , timeout )
}
}
// createOnlyLocalNodePortService creates a loadbalancer service and sanity checks its
// nodePort. If createPod is true, it also creates an RC with 1 replica of
// the standard netexec container used everywhere in this test.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) createOnlyLocalNodePortService ( namespace , serviceName string , createPod bool ) * v1 . Service {
2016-10-22 01:44:15 +00:00
By ( "creating a service " + namespace + "/" + serviceName + " with type=NodePort and annotation for local-traffic-only" )
2016-11-18 20:55:17 +00:00
svc := j . CreateTCPServiceOrFail ( namespace , func ( svc * v1 . Service ) {
svc . Spec . Type = v1 . ServiceTypeNodePort
2016-10-03 18:53:28 +00:00
svc . ObjectMeta . Annotations = map [ string ] string {
2016-10-19 01:43:13 +00:00
service . BetaAnnotationExternalTraffic : service . AnnotationValueExternalTrafficLocal }
2016-11-18 20:55:17 +00:00
svc . Spec . Ports = [ ] v1 . ServicePort { { Protocol : "TCP" , Port : 80 } }
2016-10-03 18:53:28 +00:00
} )
if createPod {
By ( "creating a pod to be part of the service " + serviceName )
j . RunOrFail ( namespace , nil )
}
2016-11-18 20:55:17 +00:00
j . SanityCheckService ( svc , v1 . ServiceTypeNodePort )
2016-10-03 18:53:28 +00:00
return svc
}
// createOnlyLocalLoadBalancerService creates a loadbalancer service and waits for it to
// acquire an ingress IP. If createPod is true, it also creates an RC with 1
// replica of the standard netexec container used everywhere in this test.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) createOnlyLocalLoadBalancerService ( namespace , serviceName string , timeout time . Duration , createPod bool ) * v1 . Service {
2016-10-22 01:44:15 +00:00
By ( "creating a service " + namespace + "/" + serviceName + " with type=LoadBalancer and annotation for local-traffic-only" )
2016-11-18 20:55:17 +00:00
svc := j . CreateTCPServiceOrFail ( namespace , func ( svc * v1 . Service ) {
svc . Spec . Type = v1 . ServiceTypeLoadBalancer
2016-10-03 18:53:28 +00:00
// We need to turn affinity off for our LB distribution tests
2016-11-18 20:55:17 +00:00
svc . Spec . SessionAffinity = v1 . ServiceAffinityNone
2016-10-03 18:53:28 +00:00
svc . ObjectMeta . Annotations = map [ string ] string {
2016-10-19 01:43:13 +00:00
service . BetaAnnotationExternalTraffic : service . AnnotationValueExternalTrafficLocal }
2016-11-18 20:55:17 +00:00
svc . Spec . Ports = [ ] v1 . ServicePort { { Protocol : "TCP" , Port : 80 } }
2016-10-03 18:53:28 +00:00
} )
if createPod {
By ( "creating a pod to be part of the service " + serviceName )
j . RunOrFail ( namespace , nil )
}
By ( "waiting for loadbalancer for service " + namespace + "/" + serviceName )
svc = j . WaitForLoadBalancerOrFail ( namespace , serviceName , timeout )
2016-11-18 20:55:17 +00:00
j . SanityCheckService ( svc , v1 . ServiceTypeLoadBalancer )
2016-10-03 18:53:28 +00:00
return svc
}
// getEndpointNodes returns a map of nodenames:external-ip on which the
// endpoints of the given Service are running.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) getEndpointNodes ( svc * v1 . Service ) map [ string ] [ ] string {
2016-10-03 18:53:28 +00:00
nodes := j . getNodes ( maxNodesForEndpointsTests )
2016-10-18 13:00:38 +00:00
endpoints , err := j . Client . Core ( ) . Endpoints ( svc . Namespace ) . Get ( svc . Name )
2016-10-03 18:53:28 +00:00
if err != nil {
framework . Failf ( "Get endpoints for service %s/%s failed (%s)" , svc . Namespace , svc . Name , err )
}
if len ( endpoints . Subsets ) == 0 {
framework . Failf ( "Endpoint has no subsets, cannot determine node addresses." )
}
epNodes := sets . NewString ( )
for _ , ss := range endpoints . Subsets {
for _ , e := range ss . Addresses {
if e . NodeName != nil {
epNodes . Insert ( * e . NodeName )
}
}
}
nodeMap := map [ string ] [ ] string { }
for _ , n := range nodes . Items {
if epNodes . Has ( n . Name ) {
2016-11-18 20:55:17 +00:00
nodeMap [ n . Name ] = getNodeAddresses ( & n , v1 . NodeExternalIP )
2016-10-03 18:53:28 +00:00
}
}
return nodeMap
}
// getNodes returns the first maxNodesForTest nodes. Useful in large clusters
// where we don't eg: want to create an endpoint per node.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) getNodes ( maxNodesForTest int ) ( nodes * v1 . NodeList ) {
2016-10-18 13:00:38 +00:00
nodes = framework . GetReadySchedulableNodesOrDie ( j . Client )
2016-10-03 18:53:28 +00:00
if len ( nodes . Items ) <= maxNodesForTest {
maxNodesForTest = len ( nodes . Items )
}
nodes . Items = nodes . Items [ : maxNodesForTest ]
return nodes
}
func ( j * ServiceTestJig ) waitForEndpointOnNode ( namespace , serviceName , nodeName string ) {
err := wait . PollImmediate ( framework . Poll , loadBalancerCreateTimeoutDefault , func ( ) ( bool , error ) {
2016-10-18 13:00:38 +00:00
endpoints , err := j . Client . Core ( ) . Endpoints ( namespace ) . Get ( serviceName )
2016-10-03 18:53:28 +00:00
if err != nil {
framework . Logf ( "Get endpoints for service %s/%s failed (%s)" , namespace , serviceName , err )
return false , nil
}
// TODO: Handle multiple endpoints
if len ( endpoints . Subsets [ 0 ] . Addresses ) == 0 {
framework . Logf ( "Expected Ready endpoints - found none" )
return false , nil
}
epHostName := * endpoints . Subsets [ 0 ] . Addresses [ 0 ] . NodeName
framework . Logf ( "Pod for service %s/%s is on node %s" , namespace , serviceName , epHostName )
if epHostName != nodeName {
framework . Logf ( "Found endpoint on wrong node, expected %v, got %v" , nodeName , epHostName )
return false , nil
}
return true , nil
} )
framework . ExpectNoError ( err )
}
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) SanityCheckService ( svc * v1 . Service , svcType v1 . ServiceType ) {
2016-01-30 04:35:32 +00:00
if svc . Spec . Type != svcType {
2016-04-07 17:21:31 +00:00
framework . Failf ( "unexpected Spec.Type (%s) for service, expected %s" , svc . Spec . Type , svcType )
2016-01-30 04:35:32 +00:00
}
expectNodePorts := false
2016-11-18 20:55:17 +00:00
if svcType != v1 . ServiceTypeClusterIP {
2016-01-30 04:35:32 +00:00
expectNodePorts = true
}
for i , port := range svc . Spec . Ports {
hasNodePort := ( port . NodePort != 0 )
if hasNodePort != expectNodePorts {
2016-04-07 17:21:31 +00:00
framework . Failf ( "unexpected Spec.Ports[%d].NodePort (%d) for service" , i , port . NodePort )
2016-01-30 04:35:32 +00:00
}
if hasNodePort {
2016-04-27 04:35:14 +00:00
if ! ServiceNodePortRange . Contains ( int ( port . NodePort ) ) {
2016-04-07 17:21:31 +00:00
framework . Failf ( "out-of-range nodePort (%d) for service" , port . NodePort )
2016-01-30 04:35:32 +00:00
}
}
}
expectIngress := false
2016-11-18 20:55:17 +00:00
if svcType == v1 . ServiceTypeLoadBalancer {
2016-01-30 04:35:32 +00:00
expectIngress = true
}
hasIngress := len ( svc . Status . LoadBalancer . Ingress ) != 0
if hasIngress != expectIngress {
2016-04-07 17:21:31 +00:00
framework . Failf ( "unexpected number of Status.LoadBalancer.Ingress (%d) for service" , len ( svc . Status . LoadBalancer . Ingress ) )
2016-01-30 04:35:32 +00:00
}
if hasIngress {
for i , ing := range svc . Status . LoadBalancer . Ingress {
if ing . IP == "" && ing . Hostname == "" {
2016-04-07 17:21:31 +00:00
framework . Failf ( "unexpected Status.LoadBalancer.Ingress[%d] for service: %#v" , i , ing )
2016-01-30 04:35:32 +00:00
}
}
}
}
// UpdateService fetches a service, calls the update function on it, and
// then attempts to send the updated service. It tries up to 3 times in the
// face of timeouts and conflicts.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) UpdateService ( namespace , name string , update func ( * v1 . Service ) ) ( * v1 . Service , error ) {
2016-01-30 04:35:32 +00:00
for i := 0 ; i < 3 ; i ++ {
2016-10-18 13:00:38 +00:00
service , err := j . Client . Core ( ) . Services ( namespace ) . Get ( name )
2016-01-30 04:35:32 +00:00
if err != nil {
return nil , fmt . Errorf ( "Failed to get Service %q: %v" , name , err )
}
update ( service )
2016-10-18 13:00:38 +00:00
service , err = j . Client . Core ( ) . Services ( namespace ) . Update ( service )
2016-01-30 04:35:32 +00:00
if err == nil {
return service , nil
}
if ! errors . IsConflict ( err ) && ! errors . IsServerTimeout ( err ) {
return nil , fmt . Errorf ( "Failed to update Service %q: %v" , name , err )
}
}
return nil , fmt . Errorf ( "Too many retries updating Service %q" , name )
}
// UpdateServiceOrFail fetches a service, calls the update function on it, and
// then attempts to send the updated service. It tries up to 3 times in the
// face of timeouts and conflicts.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) UpdateServiceOrFail ( namespace , name string , update func ( * v1 . Service ) ) * v1 . Service {
2016-01-30 04:35:32 +00:00
svc , err := j . UpdateService ( namespace , name , update )
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( err . Error ( ) )
2016-01-30 04:35:32 +00:00
}
return svc
}
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) ChangeServiceNodePortOrFail ( namespace , name string , initial int ) * v1 . Service {
2016-01-30 04:35:32 +00:00
var err error
2016-11-18 20:55:17 +00:00
var service * v1 . Service
2016-01-30 04:35:32 +00:00
for i := 1 ; i < ServiceNodePortRange . Size ; i ++ {
offs1 := initial - ServiceNodePortRange . Base
offs2 := ( offs1 + i ) % ServiceNodePortRange . Size
newPort := ServiceNodePortRange . Base + offs2
2016-11-18 20:55:17 +00:00
service , err = j . UpdateService ( namespace , name , func ( s * v1 . Service ) {
2016-04-27 04:35:14 +00:00
s . Spec . Ports [ 0 ] . NodePort = int32 ( newPort )
2016-01-30 04:35:32 +00:00
} )
if err != nil && strings . Contains ( err . Error ( ) , "provided port is already allocated" ) {
2016-04-07 17:21:31 +00:00
framework . Logf ( "tried nodePort %d, but it is in use, will try another" , newPort )
2016-01-30 04:35:32 +00:00
continue
}
// Otherwise err was nil or err was a real error
break
}
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Could not change the nodePort: %v" , err )
2016-01-30 04:35:32 +00:00
}
return service
}
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) WaitForLoadBalancerOrFail ( namespace , name string , timeout time . Duration ) * v1 . Service {
var service * v1 . Service
2016-08-02 10:30:14 +00:00
framework . Logf ( "Waiting up to %v for service %q to have a LoadBalancer" , timeout , name )
2016-01-30 04:35:32 +00:00
pollFunc := func ( ) ( bool , error ) {
2016-10-18 13:00:38 +00:00
svc , err := j . Client . Core ( ) . Services ( namespace ) . Get ( name )
2016-01-30 04:35:32 +00:00
if err != nil {
return false , err
}
if len ( svc . Status . LoadBalancer . Ingress ) > 0 {
service = svc
return true , nil
}
return false , nil
}
2016-08-02 10:30:14 +00:00
if err := wait . PollImmediate ( framework . Poll , timeout , pollFunc ) ; err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Timeout waiting for service %q to have a load balancer" , name )
2016-01-30 04:35:32 +00:00
}
return service
}
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) WaitForLoadBalancerDestroyOrFail ( namespace , name string , ip string , port int , timeout time . Duration ) * v1 . Service {
2016-01-30 04:35:32 +00:00
// TODO: once support ticket 21807001 is resolved, reduce this timeout back to something reasonable
defer func ( ) {
2016-04-07 17:21:31 +00:00
if err := framework . EnsureLoadBalancerResourcesDeleted ( ip , strconv . Itoa ( port ) ) ; err != nil {
framework . Logf ( "Failed to delete cloud resources for service: %s %d (%v)" , ip , port , err )
2016-01-30 04:35:32 +00:00
}
} ( )
2016-11-18 20:55:17 +00:00
var service * v1 . Service
2016-08-02 10:30:14 +00:00
framework . Logf ( "Waiting up to %v for service %q to have no LoadBalancer" , timeout , name )
2016-01-30 04:35:32 +00:00
pollFunc := func ( ) ( bool , error ) {
2016-10-18 13:00:38 +00:00
svc , err := j . Client . Core ( ) . Services ( namespace ) . Get ( name )
2016-01-30 04:35:32 +00:00
if err != nil {
return false , err
}
if len ( svc . Status . LoadBalancer . Ingress ) == 0 {
service = svc
return true , nil
}
return false , nil
}
2016-08-02 10:30:14 +00:00
if err := wait . PollImmediate ( framework . Poll , timeout , pollFunc ) ; err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Timeout waiting for service %q to have no load balancer" , name )
2016-01-30 04:35:32 +00:00
}
return service
}
func ( j * ServiceTestJig ) TestReachableHTTP ( host string , port int , timeout time . Duration ) {
2016-04-07 17:21:31 +00:00
if err := wait . PollImmediate ( framework . Poll , timeout , func ( ) ( bool , error ) { return testReachableHTTP ( host , port , "/echo?msg=hello" , "hello" ) } ) ; err != nil {
framework . Failf ( "Could not reach HTTP service through %v:%v after %v: %v" , host , port , timeout , err )
2016-01-30 04:35:32 +00:00
}
}
func ( j * ServiceTestJig ) TestNotReachableHTTP ( host string , port int , timeout time . Duration ) {
2016-04-07 17:21:31 +00:00
if err := wait . PollImmediate ( framework . Poll , timeout , func ( ) ( bool , error ) { return testNotReachableHTTP ( host , port ) } ) ; err != nil {
framework . Failf ( "Could still reach HTTP service through %v:%v after %v: %v" , host , port , timeout , err )
2016-01-30 04:35:32 +00:00
}
}
func ( j * ServiceTestJig ) TestReachableUDP ( host string , port int , timeout time . Duration ) {
2016-04-07 17:21:31 +00:00
if err := wait . PollImmediate ( framework . Poll , timeout , func ( ) ( bool , error ) { return testReachableUDP ( host , port , "echo hello" , "hello" ) } ) ; err != nil {
framework . Failf ( "Could not reach UDP service through %v:%v after %v: %v" , host , port , timeout , err )
2016-01-30 04:35:32 +00:00
}
}
func ( j * ServiceTestJig ) TestNotReachableUDP ( host string , port int , timeout time . Duration ) {
2016-04-07 17:21:31 +00:00
if err := wait . PollImmediate ( framework . Poll , timeout , func ( ) ( bool , error ) { return testNotReachableUDP ( host , port , "echo hello" ) } ) ; err != nil {
framework . Failf ( "Could still reach UDP service through %v:%v after %v: %v" , host , port , timeout , err )
2016-01-30 04:35:32 +00:00
}
}
2016-08-22 17:48:00 +00:00
func ( j * ServiceTestJig ) GetHTTPContent ( host string , port int , timeout time . Duration , url string ) bytes . Buffer {
var body bytes . Buffer
2016-10-03 18:53:28 +00:00
var err error
if pollErr := wait . PollImmediate ( framework . Poll , timeout , func ( ) ( bool , error ) {
result , err := testReachableHTTPWithContent ( host , port , url , "" , & body )
if err != nil {
framework . Logf ( "Error hitting %v:%v%v, retrying: %v" , host , port , url , err )
return false , nil
}
return result , nil
} ) ; pollErr != nil {
framework . Failf ( "Could not reach HTTP service through %v:%v%v after %v: %v" , host , port , url , timeout , err )
2016-08-22 17:48:00 +00:00
}
return body
}
2016-10-03 18:53:28 +00:00
func ( j * ServiceTestJig ) TestHTTPHealthCheckNodePort ( host string , port int , request string , tries int ) ( pass , fail int , statusMsg string ) {
for i := 0 ; i < tries ; i ++ {
success , err := testHTTPHealthCheckNodePort ( host , port , request )
if success {
pass ++
} else {
fail ++
}
statusMsg += fmt . Sprintf ( "\nAttempt %d Error %v" , i , err )
time . Sleep ( 1 * time . Second )
2016-08-22 17:48:00 +00:00
}
2016-10-03 18:53:28 +00:00
return pass , fail , statusMsg
2016-08-22 17:48:00 +00:00
}
2016-11-18 20:55:17 +00:00
func getIngressPoint ( ing * v1 . LoadBalancerIngress ) string {
2016-01-30 04:35:32 +00:00
host := ing . IP
if host == "" {
host = ing . Hostname
}
return host
}
2016-11-18 20:55:17 +00:00
// newRCTemplate returns the default v1.ReplicationController object for
2016-01-30 04:35:32 +00:00
// this jig, but does not actually create the RC. The default RC has the same
// name as the jig and runs the "netexec" container.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) newRCTemplate ( namespace string ) * v1 . ReplicationController {
rc := & v1 . ReplicationController {
ObjectMeta : v1 . ObjectMeta {
2016-01-30 04:35:32 +00:00
Namespace : namespace ,
Name : j . Name ,
Labels : j . Labels ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . ReplicationControllerSpec {
Replicas : func ( i int ) * int32 { x := int32 ( i ) ; return & x } ( 1 ) ,
2016-01-30 04:35:32 +00:00
Selector : j . Labels ,
2016-11-18 20:55:17 +00:00
Template : & v1 . PodTemplateSpec {
ObjectMeta : v1 . ObjectMeta {
2016-01-30 04:35:32 +00:00
Labels : j . Labels ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-01-30 04:35:32 +00:00
{
Name : "netexec" ,
2016-09-18 23:26:07 +00:00
Image : "gcr.io/google_containers/netexec:1.7" ,
2016-01-30 04:35:32 +00:00
Args : [ ] string { "--http-port=80" , "--udp-port=80" } ,
2016-11-18 20:55:17 +00:00
ReadinessProbe : & v1 . Probe {
2016-01-30 04:35:32 +00:00
PeriodSeconds : 3 ,
2016-11-18 20:55:17 +00:00
Handler : v1 . Handler {
HTTPGet : & v1 . HTTPGetAction {
2016-01-30 04:35:32 +00:00
Port : intstr . FromInt ( 80 ) ,
Path : "/hostName" ,
} ,
} ,
} ,
} ,
} ,
TerminationGracePeriodSeconds : new ( int64 ) ,
} ,
} ,
} ,
}
return rc
}
// RunOrFail creates a ReplicationController and Pod(s) and waits for the
// Pod(s) to be running. Callers can provide a function to tweak the RC object
// before it is created.
2016-11-18 20:55:17 +00:00
func ( j * ServiceTestJig ) RunOrFail ( namespace string , tweak func ( rc * v1 . ReplicationController ) ) * v1 . ReplicationController {
2016-01-30 04:35:32 +00:00
rc := j . newRCTemplate ( namespace )
if tweak != nil {
tweak ( rc )
}
2016-10-18 13:00:38 +00:00
result , err := j . Client . Core ( ) . ReplicationControllers ( namespace ) . Create ( rc )
2016-01-30 04:35:32 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Failed to created RC %q: %v" , rc . Name , err )
2016-01-30 04:35:32 +00:00
}
2016-11-18 20:55:17 +00:00
pods , err := j . waitForPodsCreated ( namespace , int ( * ( rc . Spec . Replicas ) ) )
2016-01-30 04:35:32 +00:00
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Failed to create pods: %v" , err )
2016-01-30 04:35:32 +00:00
}
if err := j . waitForPodsReady ( namespace , pods ) ; err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Failed waiting for pods to be running: %v" , err )
2016-01-30 04:35:32 +00:00
}
return result
}
func ( j * ServiceTestJig ) waitForPodsCreated ( namespace string , replicas int ) ( [ ] string , error ) {
timeout := 2 * time . Minute
// List the pods, making sure we observe all the replicas.
label := labels . SelectorFromSet ( labels . Set ( j . Labels ) )
2016-04-07 17:21:31 +00:00
framework . Logf ( "Waiting up to %v for %d pods to be created" , timeout , replicas )
2016-01-30 04:35:32 +00:00
for start := time . Now ( ) ; time . Since ( start ) < timeout ; time . Sleep ( 2 * time . Second ) {
2016-11-18 20:55:17 +00:00
options := v1 . ListOptions { LabelSelector : label . String ( ) }
2016-10-18 13:00:38 +00:00
pods , err := j . Client . Core ( ) . Pods ( namespace ) . List ( options )
2016-01-30 04:35:32 +00:00
if err != nil {
return nil , err
}
found := [ ] string { }
for _ , pod := range pods . Items {
if pod . DeletionTimestamp != nil {
continue
}
found = append ( found , pod . Name )
}
if len ( found ) == replicas {
2016-04-07 17:21:31 +00:00
framework . Logf ( "Found all %d pods" , replicas )
2016-01-30 04:35:32 +00:00
return found , nil
}
2016-04-07 17:21:31 +00:00
framework . Logf ( "Found %d/%d pods - will retry" , len ( found ) , replicas )
2016-01-30 04:35:32 +00:00
}
return nil , fmt . Errorf ( "Timeout waiting for %d pods to be created" , replicas )
}
func ( j * ServiceTestJig ) waitForPodsReady ( namespace string , pods [ ] string ) error {
timeout := 2 * time . Minute
2016-04-07 17:21:31 +00:00
if ! framework . CheckPodsRunningReady ( j . Client , namespace , pods , timeout ) {
2016-02-06 14:15:55 +00:00
return fmt . Errorf ( "Timeout waiting for %d pods to be ready" , len ( pods ) )
2016-01-30 04:35:32 +00:00
}
return nil
}
2015-05-22 23:01:35 +00:00
// Simple helper class to avoid too much boilerplate in tests
2016-01-29 22:56:37 +00:00
type ServiceTestFixture struct {
2015-05-22 23:01:35 +00:00
ServiceName string
Namespace string
2016-10-18 13:00:38 +00:00
Client clientset . Interface
2015-05-22 23:01:35 +00:00
TestId string
Labels map [ string ] string
2015-06-17 07:13:26 +00:00
rcs map [ string ] bool
2015-05-22 23:01:35 +00:00
services map [ string ] bool
2015-06-17 07:13:26 +00:00
name string
image string
2015-05-22 23:01:35 +00:00
}
2016-10-18 13:00:38 +00:00
func NewServerTest ( client clientset . Interface , namespace string , serviceName string ) * ServiceTestFixture {
2016-01-29 22:56:37 +00:00
t := & ServiceTestFixture { }
2015-05-22 23:01:35 +00:00
t . Client = client
t . Namespace = namespace
t . ServiceName = serviceName
2016-07-26 15:13:18 +00:00
t . TestId = t . ServiceName + "-" + string ( uuid . NewUUID ( ) )
2015-05-22 23:01:35 +00:00
t . Labels = map [ string ] string {
"testid" : t . TestId ,
}
2015-06-17 07:13:26 +00:00
t . rcs = make ( map [ string ] bool )
2015-05-22 23:01:35 +00:00
t . services = make ( map [ string ] bool )
2015-06-17 07:13:26 +00:00
t . name = "webserver"
2016-02-20 04:22:49 +00:00
t . image = "gcr.io/google_containers/test-webserver:e2e"
2015-05-22 23:01:35 +00:00
2015-06-17 07:13:26 +00:00
return t
2015-05-22 23:01:35 +00:00
}
// Build default config for a service (which can then be changed)
2016-11-18 20:55:17 +00:00
func ( t * ServiceTestFixture ) BuildServiceSpec ( ) * v1 . Service {
service := & v1 . Service {
ObjectMeta : v1 . ObjectMeta {
2015-10-01 22:16:12 +00:00
Name : t . ServiceName ,
Namespace : t . Namespace ,
2015-05-22 23:01:35 +00:00
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . ServiceSpec {
2015-05-22 23:01:35 +00:00
Selector : t . Labels ,
2016-11-18 20:55:17 +00:00
Ports : [ ] v1 . ServicePort { {
2015-05-22 23:01:35 +00:00
Port : 80 ,
2015-11-10 06:28:45 +00:00
TargetPort : intstr . FromInt ( 80 ) ,
2015-05-22 23:01:35 +00:00
} } ,
} ,
}
return service
}
2015-06-17 07:13:26 +00:00
// CreateWebserverRC creates rc-backed pods with the well-known webserver
// configuration and records it for cleanup.
2016-11-18 20:55:17 +00:00
func ( t * ServiceTestFixture ) CreateWebserverRC ( replicas int32 ) * v1 . ReplicationController {
rcSpec := rcByNamePort ( t . name , replicas , t . image , 80 , v1 . ProtocolTCP , t . Labels , nil )
2015-09-28 20:57:58 +00:00
rcAct , err := t . createRC ( rcSpec )
if err != nil {
2016-04-07 17:21:31 +00:00
framework . Failf ( "Failed to create rc %s: %v" , rcSpec . Name , err )
2015-09-28 20:57:58 +00:00
}
2016-04-07 17:21:31 +00:00
if err := framework . VerifyPods ( t . Client , t . Namespace , t . name , false , replicas ) ; err != nil {
framework . Failf ( "Failed to create %d pods with name %s: %v" , replicas , t . name , err )
2015-09-28 20:57:58 +00:00
}
return rcAct
}
2015-06-17 07:13:26 +00:00
// createRC creates a replication controller and records it for cleanup.
2016-11-18 20:55:17 +00:00
func ( t * ServiceTestFixture ) createRC ( rc * v1 . ReplicationController ) ( * v1 . ReplicationController , error ) {
2016-10-18 13:00:38 +00:00
rc , err := t . Client . Core ( ) . ReplicationControllers ( t . Namespace ) . Create ( rc )
2015-05-22 23:01:35 +00:00
if err == nil {
2015-06-17 07:13:26 +00:00
t . rcs [ rc . Name ] = true
2015-05-22 23:01:35 +00:00
}
2015-06-17 07:13:26 +00:00
return rc , err
2015-05-22 23:01:35 +00:00
}
// Create a service, and record it for cleanup
2016-11-18 20:55:17 +00:00
func ( t * ServiceTestFixture ) CreateService ( service * v1 . Service ) ( * v1 . Service , error ) {
2016-10-18 13:00:38 +00:00
result , err := t . Client . Core ( ) . Services ( t . Namespace ) . Create ( service )
2015-05-22 23:01:35 +00:00
if err == nil {
t . services [ service . Name ] = true
}
return result , err
}
// Delete a service, and remove it from the cleanup list
2016-01-29 22:56:37 +00:00
func ( t * ServiceTestFixture ) DeleteService ( serviceName string ) error {
2016-10-18 13:00:38 +00:00
err := t . Client . Core ( ) . Services ( t . Namespace ) . Delete ( serviceName , nil )
2015-05-22 23:01:35 +00:00
if err == nil {
delete ( t . services , serviceName )
}
return err
}
2016-01-29 22:56:37 +00:00
func ( t * ServiceTestFixture ) Cleanup ( ) [ ] error {
2015-05-22 23:01:35 +00:00
var errs [ ] error
2015-06-17 07:13:26 +00:00
for rcName := range t . rcs {
By ( "stopping RC " + rcName + " in namespace " + t . Namespace )
// First, resize the RC to 0.
2016-10-18 13:00:38 +00:00
old , err := t . Client . Core ( ) . ReplicationControllers ( t . Namespace ) . Get ( rcName )
2015-05-22 23:01:35 +00:00
if err != nil {
errs = append ( errs , err )
}
2016-11-18 20:55:17 +00:00
x := int32 ( 0 )
old . Spec . Replicas = & x
2016-10-18 13:00:38 +00:00
if _ , err := t . Client . Core ( ) . ReplicationControllers ( t . Namespace ) . Update ( old ) ; err != nil {
2015-06-17 07:13:26 +00:00
errs = append ( errs , err )
}
2015-08-26 17:05:34 +00:00
// TODO(mikedanese): Wait.
2015-06-17 07:13:26 +00:00
// Then, delete the RC altogether.
2016-10-18 13:00:38 +00:00
if err := t . Client . Core ( ) . ReplicationControllers ( t . Namespace ) . Delete ( rcName , nil ) ; err != nil {
2015-06-17 07:13:26 +00:00
errs = append ( errs , err )
}
2015-05-22 23:01:35 +00:00
}
for serviceName := range t . services {
By ( "deleting service " + serviceName + " in namespace " + t . Namespace )
2016-10-18 13:00:38 +00:00
err := t . Client . Core ( ) . Services ( t . Namespace ) . Delete ( serviceName , nil )
2015-05-22 23:01:35 +00:00
if err != nil {
errs = append ( errs , err )
}
}
return errs
}
2016-08-17 04:07:17 +00:00
// newEchoServerPodSpec returns the pod spec of echo server pod
2016-11-18 20:55:17 +00:00
func newEchoServerPodSpec ( podName string ) * v1 . Pod {
2016-08-17 04:07:17 +00:00
port := 8080
2016-11-18 20:55:17 +00:00
pod := & v1 . Pod {
ObjectMeta : v1 . ObjectMeta {
2016-08-17 04:07:17 +00:00
Name : podName ,
} ,
2016-11-18 20:55:17 +00:00
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
2016-08-17 04:07:17 +00:00
{
Name : "echoserver" ,
Image : "gcr.io/google_containers/echoserver:1.4" ,
2016-11-18 20:55:17 +00:00
Ports : [ ] v1 . ContainerPort { { ContainerPort : int32 ( port ) } } ,
2016-08-17 04:07:17 +00:00
} ,
} ,
2016-11-18 20:55:17 +00:00
RestartPolicy : v1 . RestartPolicyNever ,
2016-08-17 04:07:17 +00:00
} ,
}
return pod
}
// launchEchoserverPodOnNode launches a pod serving http on port 8080 to act
// as the target for source IP preservation test. The client's source ip would
// be echoed back by the web server.
func ( j * ServiceTestJig ) launchEchoserverPodOnNode ( f * framework . Framework , nodeName , podName string ) {
framework . Logf ( "Creating echo server pod %q in namespace %q" , podName , f . Namespace . Name )
pod := newEchoServerPodSpec ( podName )
pod . Spec . NodeName = nodeName
pod . ObjectMeta . Labels = j . Labels
2016-10-18 13:00:38 +00:00
podClient := f . ClientSet . Core ( ) . Pods ( f . Namespace . Name )
2016-08-17 04:07:17 +00:00
_ , err := podClient . Create ( pod )
framework . ExpectNoError ( err )
framework . ExpectNoError ( f . WaitForPodRunning ( podName ) )
framework . Logf ( "Echo server pod %q in namespace %q running" , pod . Name , f . Namespace . Name )
}
2016-10-18 13:00:38 +00:00
func execSourceipTest ( f * framework . Framework , c clientset . Interface , ns , nodeName , serviceIP string , servicePort int ) ( string , string ) {
2016-10-03 18:53:28 +00:00
framework . Logf ( "Creating an exec pod on node %v" , nodeName )
2016-10-18 13:00:38 +00:00
execPodName := createExecPodOnNode ( f . ClientSet , ns , nodeName , fmt . Sprintf ( "execpod-sourceip-%s" , nodeName ) )
2016-08-17 04:07:17 +00:00
defer func ( ) {
framework . Logf ( "Cleaning up the exec pod" )
2016-10-18 13:00:38 +00:00
err := c . Core ( ) . Pods ( ns ) . Delete ( execPodName , nil )
2016-08-17 04:07:17 +00:00
Expect ( err ) . NotTo ( HaveOccurred ( ) )
} ( )
2016-10-18 13:00:38 +00:00
execPod , err := f . ClientSet . Core ( ) . Pods ( ns ) . Get ( execPodName )
2016-08-17 04:07:17 +00:00
ExpectNoError ( err )
var stdout string
timeout := 2 * time . Minute
2016-10-03 18:53:28 +00:00
framework . Logf ( "Waiting up to %v wget %s:%d" , timeout , serviceIP , servicePort )
cmd := fmt . Sprintf ( ` wget -T 30 -qO- %s:%d | grep client_address ` , serviceIP , servicePort )
2016-08-17 04:07:17 +00:00
for start := time . Now ( ) ; time . Since ( start ) < timeout ; time . Sleep ( 2 ) {
stdout , err = framework . RunHostCmd ( execPod . Namespace , execPod . Name , cmd )
if err != nil {
framework . Logf ( "got err: %v, retry until timeout" , err )
continue
}
2016-10-05 16:13:19 +00:00
// Need to check output because wget -q might omit the error.
if strings . TrimSpace ( stdout ) == "" {
framework . Logf ( "got empty stdout, retry until timeout" )
continue
}
2016-08-17 04:07:17 +00:00
break
}
ExpectNoError ( err )
2016-10-05 16:13:19 +00:00
// The stdout return from RunHostCmd seems to come with "\n", so TrimSpace is needed.
// Desired stdout in this format: client_address=x.x.x.x
2016-08-17 04:07:17 +00:00
outputs := strings . Split ( strings . TrimSpace ( stdout ) , "=" )
2016-10-04 17:23:53 +00:00
if len ( outputs ) != 2 {
2016-10-05 16:13:19 +00:00
// Fail the test if output format is unexpected.
2016-10-04 17:23:53 +00:00
framework . Failf ( "exec pod returned unexpected stdout format: [%v]\n" , stdout )
}
2016-10-03 18:53:28 +00:00
return execPod . Status . PodIP , outputs [ 1 ]
2016-08-17 04:07:17 +00:00
}
2016-09-07 02:48:04 +00:00
2016-11-18 20:55:17 +00:00
func getLoadBalancerName ( service * v1 . Service ) string {
2016-09-07 02:48:04 +00:00
//GCE requires that the name of a load balancer starts with a lower case letter.
ret := "a" + string ( service . UID )
ret = strings . Replace ( ret , "-" , "" , - 1 )
//AWS requires that the name of a load balancer is shorter than 32 bytes.
if len ( ret ) > 32 {
ret = ret [ : 32 ]
}
return ret
}
func cleanupServiceGCEResources ( loadBalancerName string ) {
if pollErr := wait . Poll ( 5 * time . Second , lbCleanupTimeout , func ( ) ( bool , error ) {
if err := framework . CleanupGCEResources ( loadBalancerName ) ; err != nil {
framework . Logf ( "Still waiting for glbc to cleanup: %v" , err )
return false , nil
}
return true , nil
} ) ; pollErr != nil {
framework . Failf ( "Failed to cleanup service GCE resources." )
}
}
func describeSvc ( ns string ) {
framework . Logf ( "\nOutput of kubectl describe svc:\n" )
desc , _ := framework . RunKubectl (
"describe" , "svc" , fmt . Sprintf ( "--namespace=%v" , ns ) )
framework . Logf ( desc )
}
2016-09-15 00:00:00 +00:00
func checkReachabilityFromPod ( expectToBeReachable bool , namespace , pod , target string ) {
cmd := fmt . Sprintf ( "wget -T 5 -qO- %q" , target )
err := wait . PollImmediate ( framework . Poll , 2 * time . Minute , func ( ) ( bool , error ) {
_ , err := framework . RunHostCmd ( namespace , pod , cmd )
if expectToBeReachable && err != nil {
framework . Logf ( "Expect target to be reachable. But got err: %v. Retry until timeout" , err )
return false , nil
}
if ! expectToBeReachable && err == nil {
framework . Logf ( "Expect target NOT to be reachable. But it is reachable. Retry until timeout" )
return false , nil
}
return true , nil
} )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
}