2016-06-07 09:16:18 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2016 The Kubernetes Authors .
2016-06-07 09:16:18 +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-06-13 10:00:49 +00:00
"fmt"
"os"
2016-06-24 00:02:49 +00:00
"reflect"
"strconv"
2016-06-07 09:16:18 +00:00
"time"
"k8s.io/kubernetes/federation/apis/federation"
2016-06-14 20:07:02 +00:00
"k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_3"
2016-06-07 09:16:18 +00:00
"k8s.io/kubernetes/pkg/api"
2016-06-22 23:47:35 +00:00
"k8s.io/kubernetes/pkg/api/errors"
2016-06-07 09:16:18 +00:00
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/clientset_generated/release_1_3"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
"k8s.io/kubernetes/pkg/util/intstr"
2016-06-13 10:00:49 +00:00
"k8s.io/kubernetes/pkg/util/wait"
2016-06-07 09:16:18 +00:00
"k8s.io/kubernetes/test/e2e/framework"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
const (
UserAgentName = "federation-e2e-service-controller"
// TODO(madhusudancs): Using the same values as defined in the federated
// service controller. Replace it with the values from the e2e framework.
KubeAPIQPS = 20.0
KubeAPIBurst = 30
2016-06-17 04:07:39 +00:00
FederatedServiceTimeout = 60 * time . Second
2016-06-07 09:16:18 +00:00
2016-06-24 00:02:49 +00:00
FederatedServiceName = "federated-service"
FederatedServicePodName = "federated-service-test-pod"
2016-06-07 09:16:18 +00:00
2016-06-14 20:14:58 +00:00
DefaultFederationName = "federation"
2016-06-17 17:49:23 +00:00
// We use this to decide how long to wait for our DNS probes to succeed.
2016-06-24 00:02:49 +00:00
DNSTTL = 180 * time . Second // TODO: make k8s.io/kubernetes/federation/pkg/federation-controller/service.minDnsTtl exported, and import it here.
2016-06-07 09:16:18 +00:00
)
2016-06-23 20:12:44 +00:00
var FederatedServiceLabels = map [ string ] string {
"foo" : "bar" ,
}
2016-07-01 17:34:46 +00:00
/ *
2016-07-06 18:41:35 +00:00
cluster keeps track of the assorted objects and state related to each cluster
in the federation
2016-07-01 17:34:46 +00:00
* /
2016-07-01 16:50:57 +00:00
type cluster struct {
2016-07-01 21:54:29 +00:00
name string
2016-07-01 16:50:57 +00:00
* release_1_3 . Clientset
2016-07-01 21:54:29 +00:00
namespaceCreated bool // Did we need to create a new namespace in this cluster? If so, we should delete it.
backendPod * v1 . Pod // The backend pod, if one's been created.
2016-07-01 16:50:57 +00:00
}
2016-06-24 00:02:49 +00:00
var _ = framework . KubeDescribe ( "[Feature:Federation]" , func ( ) {
f := framework . NewDefaultFederatedFramework ( "federated-service" )
2016-07-06 18:41:35 +00:00
var clusters map [ string ] * cluster // All clusters, keyed by cluster name
2016-06-13 10:00:49 +00:00
var federationName string
2016-07-01 21:54:29 +00:00
var primaryClusterName string // The name of the "primary" cluster
2016-06-07 09:16:18 +00:00
2016-06-24 00:02:49 +00:00
var _ = Describe ( "Federated Services" , func ( ) {
BeforeEach ( func ( ) {
framework . SkipUnlessFederated ( f . Client )
2016-06-13 10:00:49 +00:00
2016-06-24 00:02:49 +00:00
// TODO: Federation API server should be able to answer this.
if federationName = os . Getenv ( "FEDERATION_NAME" ) ; federationName == "" {
federationName = DefaultFederationName
}
2016-06-13 10:00:49 +00:00
2016-06-24 00:02:49 +00:00
contexts := f . GetUnderlyingFederatedContexts ( )
2016-06-07 09:16:18 +00:00
2016-06-24 00:02:49 +00:00
for _ , context := range contexts {
createClusterObjectOrFail ( f , & context )
2016-06-13 10:00:49 +00:00
}
2016-06-07 09:16:18 +00:00
2016-06-24 00:02:49 +00:00
var clusterList * federation . ClusterList
By ( "Obtaining a list of all the clusters" )
if err := wait . PollImmediate ( framework . Poll , FederatedServiceTimeout , func ( ) ( bool , error ) {
var err error
clusterList , err = f . FederationClientset . Federation ( ) . Clusters ( ) . List ( api . ListOptions { } )
if err != nil {
return false , err
}
framework . Logf ( "%d clusters registered, waiting for %d" , len ( clusterList . Items ) , len ( contexts ) )
if len ( clusterList . Items ) == len ( contexts ) {
return true , nil
}
return false , nil
} ) ; err != nil {
framework . Failf ( "Failed to list registered clusters: %+v" , err )
}
2016-06-17 04:07:39 +00:00
2016-06-24 00:02:49 +00:00
framework . Logf ( "Checking that %d clusters are Ready" , len ( contexts ) )
for _ , context := range contexts {
clusterIsReadyOrFail ( f , & context )
}
framework . Logf ( "%d clusters are Ready" , len ( contexts ) )
2016-06-07 09:16:18 +00:00
2016-07-01 22:18:34 +00:00
clusters = map [ string ] * cluster { }
2016-07-01 21:54:29 +00:00
primaryClusterName = clusterList . Items [ 0 ] . Name
By ( fmt . Sprintf ( "Labeling %q as the first cluster" , primaryClusterName ) )
for i , c := range clusterList . Items {
framework . Logf ( "Creating a clientset for the cluster %s" , c . Name )
2016-06-07 09:16:18 +00:00
2016-06-24 00:02:49 +00:00
Expect ( framework . TestContext . KubeConfig ) . ToNot ( Equal ( "" ) , "KubeConfig must be specified to load clusters' client config" )
kubecfg , err := clientcmd . LoadFromFile ( framework . TestContext . KubeConfig )
framework . ExpectNoError ( err , "error loading KubeConfig: %v" , err )
2016-06-22 23:47:35 +00:00
2016-06-24 00:02:49 +00:00
cfgOverride := & clientcmd . ConfigOverrides {
ClusterInfo : clientcmdapi . Cluster {
2016-07-01 21:54:29 +00:00
Server : c . Spec . ServerAddressByClientCIDRs [ 0 ] . ServerAddress ,
2016-06-22 23:47:35 +00:00
} ,
}
2016-07-01 21:54:29 +00:00
ccfg := clientcmd . NewNonInteractiveClientConfig ( * kubecfg , c . Name , cfgOverride , clientcmd . NewDefaultClientConfigLoadingRules ( ) )
2016-06-24 00:02:49 +00:00
cfg , err := ccfg . ClientConfig ( )
2016-07-01 21:54:29 +00:00
framework . ExpectNoError ( err , "Error creating client config in cluster #%d (%q)" , i , c . Name )
2016-06-24 00:02:49 +00:00
cfg . QPS = KubeAPIQPS
cfg . Burst = KubeAPIBurst
clset := release_1_3 . NewForConfigOrDie ( restclient . AddUserAgent ( cfg , UserAgentName ) )
2016-07-01 22:18:34 +00:00
clusters [ c . Name ] = & cluster { c . Name , clset , false , nil }
2016-06-24 00:02:49 +00:00
}
2016-07-01 21:54:29 +00:00
for name , c := range clusters {
2016-06-24 00:02:49 +00:00
// The e2e Framework created the required namespace in one of the clusters, but we need to create it in all the others, if it doesn't yet exist.
2016-07-01 16:50:57 +00:00
if _ , err := c . Clientset . Core ( ) . Namespaces ( ) . Get ( f . Namespace . Name ) ; errors . IsNotFound ( err ) {
2016-06-24 00:02:49 +00:00
ns := & v1 . Namespace {
ObjectMeta : v1 . ObjectMeta {
Name : f . Namespace . Name ,
} ,
}
2016-07-01 16:50:57 +00:00
_ , err := c . Clientset . Core ( ) . Namespaces ( ) . Create ( ns )
2016-06-24 00:02:49 +00:00
if err == nil {
2016-07-01 17:34:46 +00:00
c . namespaceCreated = true
2016-06-24 00:02:49 +00:00
}
2016-07-01 21:54:29 +00:00
framework . ExpectNoError ( err , "Couldn't create the namespace %s in cluster %q" , f . Namespace . Name , name )
framework . Logf ( "Namespace %s created in cluster %q" , f . Namespace . Name , name )
2016-06-24 00:02:49 +00:00
} else if err != nil {
2016-07-01 21:54:29 +00:00
framework . Logf ( "Couldn't create the namespace %s in cluster %q: %v" , f . Namespace . Name , name , err )
2016-06-22 23:47:35 +00:00
}
}
2016-06-24 00:02:49 +00:00
} )
2016-06-07 09:16:18 +00:00
2016-06-23 20:12:44 +00:00
AfterEach ( func ( ) {
2016-07-01 21:54:29 +00:00
for name , c := range clusters {
2016-07-01 17:34:46 +00:00
if c . namespaceCreated {
2016-07-01 16:50:57 +00:00
if _ , err := c . Clientset . Core ( ) . Namespaces ( ) . Get ( f . Namespace . Name ) ; ! errors . IsNotFound ( err ) {
err := c . Clientset . Core ( ) . Namespaces ( ) . Delete ( f . Namespace . Name , & api . DeleteOptions { } )
2016-07-01 21:54:29 +00:00
framework . ExpectNoError ( err , "Couldn't delete the namespace %s in cluster %q: %v" , f . Namespace . Name , name , err )
2016-06-24 00:02:49 +00:00
}
2016-07-01 21:54:29 +00:00
framework . Logf ( "Namespace %s deleted in cluster %q" , f . Namespace . Name , name )
2016-06-23 20:12:44 +00:00
}
2016-06-22 23:47:35 +00:00
}
2016-06-23 20:12:44 +00:00
// Delete the registered clusters in the federation API server.
clusterList , err := f . FederationClientset . Federation ( ) . Clusters ( ) . List ( api . ListOptions { } )
2016-06-24 00:02:49 +00:00
framework . ExpectNoError ( err , "Error listing clusters" )
2016-06-23 20:12:44 +00:00
for _ , cluster := range clusterList . Items {
err := f . FederationClientset . Federation ( ) . Clusters ( ) . Delete ( cluster . Name , & api . DeleteOptions { } )
2016-06-24 00:02:49 +00:00
framework . ExpectNoError ( err , "Error deleting cluster %q" , cluster . Name )
2016-06-23 20:12:44 +00:00
}
} )
2016-06-13 10:00:49 +00:00
2016-06-24 00:02:49 +00:00
Describe ( "Service creation" , func ( ) {
BeforeEach ( func ( ) {
framework . SkipUnlessFederated ( f . Client )
// Placeholder
} )
2016-06-07 09:16:18 +00:00
2016-06-24 00:02:49 +00:00
AfterEach ( func ( ) {
framework . SkipUnlessFederated ( f . Client )
// Placeholder
} )
2016-06-07 09:16:18 +00:00
2016-06-24 00:02:49 +00:00
It ( "should succeed" , func ( ) {
framework . SkipUnlessFederated ( f . Client )
service := createServiceOrFail ( f . FederationClientset_1_3 , f . Namespace . Name )
By ( fmt . Sprintf ( "Creation of service %q in namespace %q succeeded. Deleting service." , service . Name , f . Namespace . Name ) )
// Cleanup
err := f . FederationClientset_1_3 . Services ( f . Namespace . Name ) . Delete ( service . Name , & api . DeleteOptions { } )
framework . ExpectNoError ( err , "Error deleting service %q in namespace %q" , service . Name , service . Namespace )
By ( fmt . Sprintf ( "Deletion of service %q in namespace %q succeeded." , service . Name , f . Namespace . Name ) )
} )
It ( "should create matching services in underlying clusters" , func ( ) {
framework . SkipUnlessFederated ( f . Client )
service := createServiceOrFail ( f . FederationClientset_1_3 , f . Namespace . Name )
defer func ( ) { // Cleanup
By ( fmt . Sprintf ( "Deleting service %q in namespace %q" , service . Name , f . Namespace . Name ) )
err := f . FederationClientset_1_3 . Services ( f . Namespace . Name ) . Delete ( service . Name , & api . DeleteOptions { } )
framework . ExpectNoError ( err , "Error deleting service %q in namespace %q" , service . Name , f . Namespace . Name )
} ( )
2016-07-01 21:54:29 +00:00
waitForServiceShardsOrFail ( f . Namespace . Name , service , clusters )
2016-06-24 00:02:49 +00:00
} )
2016-06-16 21:52:12 +00:00
} )
2016-06-13 10:00:49 +00:00
2016-06-24 00:02:49 +00:00
var _ = Describe ( "DNS" , func ( ) {
var (
2016-07-01 21:54:29 +00:00
service * v1 . Service
2016-06-24 00:02:49 +00:00
)
2016-06-16 21:52:12 +00:00
BeforeEach ( func ( ) {
framework . SkipUnlessFederated ( f . Client )
2016-07-01 21:54:29 +00:00
createBackendPodsOrFail ( clusters , f . Namespace . Name , FederatedServicePodName )
2016-06-24 00:02:49 +00:00
service = createServiceOrFail ( f . FederationClientset_1_3 , f . Namespace . Name )
2016-07-01 21:54:29 +00:00
waitForServiceShardsOrFail ( f . Namespace . Name , service , clusters )
2016-06-24 00:02:49 +00:00
} )
2016-06-16 21:52:12 +00:00
2016-06-24 00:02:49 +00:00
AfterEach ( func ( ) {
framework . SkipUnlessFederated ( f . Client )
2016-07-01 21:54:29 +00:00
deleteBackendPodsOrFail ( clusters , f . Namespace . Name )
2016-06-29 07:34:43 +00:00
2016-06-24 00:02:49 +00:00
if service != nil {
deleteServiceOrFail ( f . FederationClientset_1_3 , f . Namespace . Name , service . Name )
service = nil
2016-06-29 07:34:43 +00:00
} else {
By ( "No service to delete. Service is nil" )
2016-06-24 00:02:49 +00:00
}
2016-06-16 21:52:12 +00:00
} )
2016-06-24 00:02:49 +00:00
It ( "should be able to discover a federated service" , func ( ) {
2016-06-16 21:52:12 +00:00
framework . SkipUnlessFederated ( f . Client )
svcDNSNames := [ ] string {
2016-06-24 00:02:49 +00:00
FederatedServiceName ,
fmt . Sprintf ( "%s.%s" , FederatedServiceName , f . Namespace . Name ) ,
fmt . Sprintf ( "%s.%s.svc.cluster.local." , FederatedServiceName , f . Namespace . Name ) ,
2016-06-16 21:52:12 +00:00
fmt . Sprintf ( "%s.%s.%s" , FederatedServiceName , f . Namespace . Name , federationName ) ,
fmt . Sprintf ( "%s.%s.%s.svc.cluster.local." , FederatedServiceName , f . Namespace . Name , federationName ) ,
}
2016-06-24 00:02:49 +00:00
// TODO(mml): This could be much faster. We can launch all the test
// pods, perhaps in the BeforeEach, and then just poll until we get
// successes/failures from them all.
for i , DNSName := range svcDNSNames {
discoverService ( f , DNSName , true , "federated-service-e2e-discovery-pod-" + strconv . Itoa ( i ) )
2016-06-16 21:52:12 +00:00
}
2016-06-23 20:12:44 +00:00
} )
2016-06-24 00:02:49 +00:00
Context ( "non-local federated service" , func ( ) {
BeforeEach ( func ( ) {
2016-06-23 20:12:44 +00:00
framework . SkipUnlessFederated ( f . Client )
2016-06-16 21:52:12 +00:00
2016-06-24 00:02:49 +00:00
// Delete all the backend pods from the shard which is local to the discovery pod.
2016-07-01 21:54:29 +00:00
deleteOneBackendPodOrFail ( clusters [ primaryClusterName ] )
2016-06-29 07:34:43 +00:00
2016-06-24 00:02:49 +00:00
} )
It ( "should be able to discover a non-local federated service" , func ( ) {
framework . SkipUnlessFederated ( f . Client )
svcDNSNames := [ ] string {
fmt . Sprintf ( "%s.%s.%s" , FederatedServiceName , f . Namespace . Name , federationName ) ,
fmt . Sprintf ( "%s.%s.%s.svc.cluster.local." , FederatedServiceName , f . Namespace . Name , federationName ) ,
2016-06-16 21:52:12 +00:00
}
2016-06-24 00:02:49 +00:00
for i , name := range svcDNSNames {
discoverService ( f , name , true , "federated-service-e2e-discovery-pod-" + strconv . Itoa ( i ) )
2016-06-16 21:52:12 +00:00
}
2016-06-17 18:38:53 +00:00
} )
2016-06-24 00:02:49 +00:00
// TODO(mml): This currently takes 9 minutes. Consider reducing the
// TTL and/or running the pods in parallel.
Context ( "[Slow] missing local service" , func ( ) {
It ( "should never find DNS entries for a missing local service" , func ( ) {
framework . SkipUnlessFederated ( f . Client )
localSvcDNSNames := [ ] string {
FederatedServiceName ,
fmt . Sprintf ( "%s.%s" , FederatedServiceName , f . Namespace . Name ) ,
fmt . Sprintf ( "%s.%s.svc.cluster.local." , FederatedServiceName , f . Namespace . Name ) ,
}
for i , name := range localSvcDNSNames {
2016-06-29 07:34:43 +00:00
discoverService ( f , name , false , "federated-service-e2e-discovery-pod-" + strconv . Itoa ( i ) )
2016-06-24 00:02:49 +00:00
}
} )
} )
2016-06-16 21:52:12 +00:00
} )
} )
2016-06-07 09:16:18 +00:00
} )
} )
2016-06-24 00:02:49 +00:00
/ *
equivalent returns true if the two services are equivalent . Fields which are expected to differ between
federated services and the underlying cluster services ( e . g . ClusterIP , LoadBalancerIP etc ) are ignored .
* /
func equivalent ( federationService , clusterService v1 . Service ) bool {
// TODO: I think that we need a DeepCopy here to avoid clobbering our parameters.
clusterService . Spec . ClusterIP = federationService . Spec . ClusterIP
clusterService . Spec . ExternalIPs = federationService . Spec . ExternalIPs
clusterService . Spec . DeprecatedPublicIPs = federationService . Spec . DeprecatedPublicIPs
clusterService . Spec . LoadBalancerIP = federationService . Spec . LoadBalancerIP
clusterService . Spec . LoadBalancerSourceRanges = federationService . Spec . LoadBalancerSourceRanges
// N.B. We cannot iterate over the port objects directly, as their values
// only get copied and our updates will get lost.
for i := range clusterService . Spec . Ports {
clusterService . Spec . Ports [ i ] . NodePort = federationService . Spec . Ports [ i ] . NodePort
}
return reflect . DeepEqual ( clusterService . Spec , federationService . Spec )
}
/ *
waitForServiceOrFail waits until a service is either present or absent in the cluster specified by clientset .
If the condition is not met within timout , it fails the calling test .
* /
func waitForServiceOrFail ( clientset * release_1_3 . Clientset , namespace string , service * v1 . Service , present bool , timeout time . Duration ) {
By ( fmt . Sprintf ( "Fetching a federated service shard of service %q in namespace %q from cluster" , service . Name , namespace ) )
var clusterService * v1 . Service
err := wait . PollImmediate ( framework . Poll , timeout , func ( ) ( bool , error ) {
clusterService , err := clientset . Services ( namespace ) . Get ( service . Name )
2016-06-30 20:33:20 +00:00
if ( ! present ) && errors . IsNotFound ( err ) { // We want it gone, and it's gone.
By ( fmt . Sprintf ( "Success: shard of federated service %q in namespace %q in cluster is absent" , service . Name , namespace ) )
return true , nil // Success
2016-06-13 10:00:49 +00:00
}
2016-06-30 20:33:20 +00:00
if present && err == nil { // We want it present, and the Get succeeded, so we're all good.
By ( fmt . Sprintf ( "Success: shard of federated service %q in namespace %q in cluster is present" , service . Name , namespace ) )
return true , nil // Success
2016-06-07 09:16:18 +00:00
}
2016-06-30 20:33:20 +00:00
By ( fmt . Sprintf ( "Service %q in namespace %q in cluster. Found: %v, waiting for Found: %v, trying again in %s (err=%v)" , service . Name , namespace , clusterService != nil && err == nil , present , framework . Poll , err ) )
2016-06-13 10:00:49 +00:00
return false , nil
2016-06-24 00:02:49 +00:00
} )
2016-06-30 20:33:20 +00:00
framework . ExpectNoError ( err , "Failed to verify service %q in namespace %q in cluster: Present=%v" , service . Name , namespace , present )
2016-06-24 00:02:49 +00:00
if present && clusterService != nil {
Expect ( equivalent ( * clusterService , * service ) )
2016-06-07 09:16:18 +00:00
}
2016-06-24 00:02:49 +00:00
}
2016-06-07 09:16:18 +00:00
2016-06-24 00:02:49 +00:00
/ *
2016-07-01 21:54:29 +00:00
waitForServiceShardsOrFail waits for the service to appear in all clusters
2016-06-24 00:02:49 +00:00
* /
2016-07-01 22:18:34 +00:00
func waitForServiceShardsOrFail ( namespace string , service * v1 . Service , clusters map [ string ] * cluster ) {
2016-07-01 16:50:57 +00:00
framework . Logf ( "Waiting for service %q in %d clusters" , service . Name , len ( clusters ) )
2016-07-01 21:54:29 +00:00
for _ , c := range clusters {
waitForServiceOrFail ( c . Clientset , namespace , service , true , FederatedServiceTimeout )
2016-06-07 09:16:18 +00:00
}
}
2016-06-24 00:02:49 +00:00
func createServiceOrFail ( clientset * federation_release_1_3 . Clientset , namespace string ) * v1 . Service {
if clientset == nil || len ( namespace ) == 0 {
Fail ( fmt . Sprintf ( "Internal error: invalid parameters passed to deleteServiceOrFail: clientset: %v, namespace: %v" , clientset , namespace ) )
}
2016-06-16 21:52:12 +00:00
By ( fmt . Sprintf ( "Creating federated service %q in namespace %q" , FederatedServiceName , namespace ) )
2016-06-14 20:07:02 +00:00
service := & v1 . Service {
ObjectMeta : v1 . ObjectMeta {
2016-06-07 09:16:18 +00:00
Name : FederatedServiceName ,
} ,
2016-06-14 20:07:02 +00:00
Spec : v1 . ServiceSpec {
2016-06-23 20:12:44 +00:00
Selector : FederatedServiceLabels ,
Type : "LoadBalancer" ,
2016-06-14 20:07:02 +00:00
Ports : [ ] v1 . ServicePort {
2016-06-07 09:16:18 +00:00
{
2016-06-23 20:12:44 +00:00
Name : "http" ,
2016-06-07 09:16:18 +00:00
Port : 80 ,
2016-06-23 20:12:44 +00:00
TargetPort : intstr . FromInt ( 8080 ) ,
2016-06-07 09:16:18 +00:00
} ,
} ,
} ,
}
2016-06-24 00:02:49 +00:00
By ( fmt . Sprintf ( "Trying to create service %q in namespace %q" , service . Name , namespace ) )
_ , err := clientset . Services ( namespace ) . Create ( service )
framework . ExpectNoError ( err , "Creating service %q in namespace %q" , service . Name , namespace )
By ( fmt . Sprintf ( "Successfully created federated service %q in namespace %q" , FederatedServiceName , namespace ) )
return service
}
func deleteServiceOrFail ( clientset * federation_release_1_3 . Clientset , namespace string , serviceName string ) {
if clientset == nil || len ( namespace ) == 0 || len ( serviceName ) == 0 {
Fail ( fmt . Sprintf ( "Internal error: invalid parameters passed to deleteServiceOrFail: clientset: %v, namespace: %v, service: %v" , clientset , namespace , serviceName ) )
2016-06-07 09:16:18 +00:00
}
2016-06-24 00:02:49 +00:00
err := clientset . Services ( namespace ) . Delete ( serviceName , api . NewDeleteOptions ( 0 ) )
framework . ExpectNoError ( err , "Error deleting service %q from namespace %q" , serviceName , namespace )
2016-06-07 09:16:18 +00:00
}
2016-06-17 18:39:39 +00:00
func podExitCodeDetector ( f * framework . Framework , name string , code int32 ) func ( ) error {
2016-06-16 21:52:12 +00:00
// If we ever get any container logs, stash them here.
logs := ""
logerr := func ( err error ) error {
if err == nil {
return nil
}
if logs == "" {
return err
}
return fmt . Errorf ( "%s (%v)" , logs , err )
2016-06-13 10:00:49 +00:00
}
2016-06-16 21:52:12 +00:00
2016-06-17 18:39:39 +00:00
return func ( ) error {
pod , err := f . Client . Pods ( f . Namespace . Name ) . Get ( name )
2016-06-16 21:52:12 +00:00
if err != nil {
return logerr ( err )
}
if len ( pod . Status . ContainerStatuses ) < 1 {
return logerr ( fmt . Errorf ( "no container statuses" ) )
}
// Best effort attempt to grab pod logs for debugging
2016-06-17 18:39:39 +00:00
logs , err = framework . GetPodLogs ( f . Client , f . Namespace . Name , name , pod . Spec . Containers [ 0 ] . Name )
2016-06-16 21:52:12 +00:00
if err != nil {
framework . Logf ( "Cannot fetch pod logs: %v" , err )
}
status := pod . Status . ContainerStatuses [ 0 ]
if status . State . Terminated == nil {
return logerr ( fmt . Errorf ( "container is not in terminated state" ) )
}
2016-06-17 18:39:39 +00:00
if status . State . Terminated . ExitCode == code {
2016-06-16 21:52:12 +00:00
return nil
}
return logerr ( fmt . Errorf ( "exited %d" , status . State . Terminated . ExitCode ) )
2016-06-17 18:39:39 +00:00
}
}
2016-06-24 00:02:49 +00:00
func discoverService ( f * framework . Framework , name string , exists bool , podName string ) {
2016-06-23 20:12:44 +00:00
command := [ ] string { "sh" , "-c" , fmt . Sprintf ( "until nslookup '%s'; do sleep 10; done" , name ) }
2016-06-17 18:39:39 +00:00
By ( fmt . Sprintf ( "Looking up %q" , name ) )
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
2016-06-24 00:02:49 +00:00
Name : podName ,
2016-06-17 18:39:39 +00:00
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "federated-service-discovery-container" ,
Image : "gcr.io/google_containers/busybox:1.24" ,
Command : command ,
} ,
} ,
RestartPolicy : api . RestartPolicyOnFailure ,
} ,
}
2016-06-29 07:34:43 +00:00
By ( fmt . Sprintf ( "Creating pod %q in namespace %q" , pod . Name , f . Namespace . Name ) )
2016-06-17 18:39:39 +00:00
_ , err := f . Client . Pods ( f . Namespace . Name ) . Create ( pod )
2016-06-24 00:02:49 +00:00
framework . ExpectNoError ( err , "Trying to create pod to run %q" , command )
2016-06-29 07:34:43 +00:00
By ( fmt . Sprintf ( "Successfully created pod %q in namespace %q" , pod . Name , f . Namespace . Name ) )
defer func ( ) {
By ( fmt . Sprintf ( "Deleting pod %q from namespace %q" , podName , f . Namespace . Name ) )
err := f . Client . Pods ( f . Namespace . Name ) . Delete ( podName , api . NewDeleteOptions ( 0 ) )
framework . ExpectNoError ( err , "Deleting pod %q from namespace %q" , podName , f . Namespace . Name )
By ( fmt . Sprintf ( "Deleted pod %q from namespace %q" , podName , f . Namespace . Name ) )
} ( )
2016-06-17 18:39:39 +00:00
if exists {
// TODO(mml): Eventually check the IP address is correct, too.
2016-06-24 00:02:49 +00:00
Eventually ( podExitCodeDetector ( f , podName , 0 ) , 3 * DNSTTL , time . Second * 2 ) .
2016-06-17 18:39:39 +00:00
Should ( BeNil ( ) , "%q should exit 0, but it never did" , command )
} else {
2016-06-29 07:34:43 +00:00
Eventually ( podExitCodeDetector ( f , podName , 0 ) , 3 * DNSTTL , time . Second * 2 ) .
ShouldNot ( BeNil ( ) , "%q should eventually not exit 0, but it always did" , command )
2016-06-17 18:39:39 +00:00
}
2016-06-07 09:16:18 +00:00
}
2016-06-23 20:12:44 +00:00
2016-06-24 00:02:49 +00:00
/ *
createBackendPodsOrFail creates one pod in each cluster , and returns the created pods ( in the same order as clusterClientSets ) .
If creation of any pod fails , the test fails ( possibly with a partially created set of pods ) . No retries are attempted .
* /
2016-07-01 22:18:34 +00:00
func createBackendPodsOrFail ( clusters map [ string ] * cluster , namespace string , name string ) {
2016-06-23 20:12:44 +00:00
pod := & v1 . Pod {
ObjectMeta : v1 . ObjectMeta {
2016-06-29 07:34:43 +00:00
Name : name ,
// Namespace: namespace,
Labels : FederatedServiceLabels ,
2016-06-23 20:12:44 +00:00
} ,
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container {
{
2016-06-24 00:02:49 +00:00
Name : name ,
2016-06-23 20:12:44 +00:00
Image : "gcr.io/google_containers/echoserver:1.4" ,
} ,
} ,
RestartPolicy : v1 . RestartPolicyAlways ,
} ,
}
2016-07-01 21:54:29 +00:00
for name , c := range clusters {
By ( fmt . Sprintf ( "Creating pod %q in namespace %q in cluster %q" , pod . Name , namespace , name ) )
2016-07-01 16:50:57 +00:00
createdPod , err := c . Clientset . Core ( ) . Pods ( namespace ) . Create ( pod )
2016-07-01 21:54:29 +00:00
framework . ExpectNoError ( err , "Creating pod %q in namespace %q in cluster %q" , name , namespace , name )
By ( fmt . Sprintf ( "Successfully created pod %q in namespace %q in cluster %q: %v" , pod . Name , namespace , name , * createdPod ) )
c . backendPod = createdPod
2016-06-24 00:02:49 +00:00
}
}
2016-06-23 20:12:44 +00:00
2016-06-24 00:02:49 +00:00
/ *
2016-07-06 18:41:35 +00:00
deleteOneBackendPodOrFail deletes exactly one backend pod which must not be nil
2016-07-01 21:54:29 +00:00
The test fails if there are any errors .
2016-06-24 00:02:49 +00:00
* /
2016-07-01 22:18:34 +00:00
func deleteOneBackendPodOrFail ( c * cluster ) {
2016-07-01 21:54:29 +00:00
pod := c . backendPod
2016-07-01 22:18:34 +00:00
Expect ( pod ) . ToNot ( BeNil ( ) )
2016-07-01 21:54:29 +00:00
err := c . Clientset . Core ( ) . Pods ( pod . Namespace ) . Delete ( pod . Name , api . NewDeleteOptions ( 0 ) )
if errors . IsNotFound ( err ) {
By ( fmt . Sprintf ( "Pod %q in namespace %q in cluster %q does not exist. No need to delete it." , pod . Name , pod . Namespace , c . name ) )
} else {
framework . ExpectNoError ( err , "Deleting pod %q in namespace %q from cluster %q" , pod . Name , pod . Namespace , c . name )
2016-06-24 00:02:49 +00:00
}
2016-07-01 21:54:29 +00:00
By ( fmt . Sprintf ( "Backend pod %q in namespace %q in cluster %q deleted or does not exist" , pod . Name , pod . Namespace , c . name ) )
}
/ *
deleteBackendPodsOrFail deletes one pod from each cluster that has one .
If deletion of any pod fails , the test fails ( possibly with a partially deleted set of pods ) . No retries are attempted .
* /
2016-07-01 22:18:34 +00:00
func deleteBackendPodsOrFail ( clusters map [ string ] * cluster , namespace string ) {
2016-07-01 21:54:29 +00:00
for name , c := range clusters {
if c . backendPod != nil {
deleteOneBackendPodOrFail ( c )
c . backendPod = nil
2016-06-29 07:34:43 +00:00
} else {
2016-07-01 21:54:29 +00:00
By ( fmt . Sprintf ( "No backend pod to delete for cluster %q" , name ) )
2016-06-24 00:02:49 +00:00
}
2016-06-23 20:12:44 +00:00
}
}