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 .
* /
2017-01-11 13:23:31 +00:00
package e2e_federation
2016-06-07 09:16:18 +00:00
import (
2016-06-13 10:00:49 +00:00
"fmt"
"os"
2016-06-24 00:02:49 +00:00
"reflect"
"strconv"
2016-12-17 00:06:06 +00:00
"strings"
2016-06-07 09:16:18 +00:00
"time"
2017-06-22 18:24:23 +00:00
"k8s.io/api/core/v1"
2017-01-13 17:48:50 +00:00
"k8s.io/apimachinery/pkg/api/errors"
2017-01-11 14:09:48 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
2017-07-10 17:54:48 +00:00
"k8s.io/client-go/kubernetes/scheme"
2016-12-17 00:06:06 +00:00
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
2016-09-14 18:35:38 +00:00
"k8s.io/kubernetes/test/e2e/framework"
2017-01-11 13:23:31 +00:00
fedframework "k8s.io/kubernetes/test/e2e_federation/framework"
2016-09-14 18:35:38 +00:00
2016-06-07 09:16:18 +00:00
. "github.com/onsi/ginkgo"
)
const (
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-23 20:12:44 +00:00
var FederatedServiceLabels = map [ string ] string {
"foo" : "bar" ,
}
2017-02-01 06:26:17 +00:00
var _ = framework . KubeDescribe ( "Federated Services [Feature:Federation]" , func ( ) {
2017-01-11 13:23:31 +00:00
f := fedframework . NewDefaultFederatedFramework ( "federated-service" )
2017-04-04 16:21:38 +00:00
var clusters fedframework . ClusterSlice
2016-06-13 10:00:49 +00:00
var federationName string
2016-06-07 09:16:18 +00:00
2017-02-01 06:26:17 +00:00
var _ = Describe ( "Without Clusters [NoCluster]" , func ( ) {
BeforeEach ( func ( ) {
fedframework . SkipUnlessFederated ( f . ClientSet )
// Placeholder
} )
AfterEach ( func ( ) {
fedframework . SkipUnlessFederated ( f . ClientSet )
} )
It ( "should succeed when a service is created" , func ( ) {
fedframework . SkipUnlessFederated ( f . ClientSet )
nsName := f . FederationNamespace . Name
service := createServiceOrFail ( f . FederationClientset , nsName , FederatedServiceName )
By ( fmt . Sprintf ( "Creation of service %q in namespace %q succeeded. Deleting service." , service . Name , nsName ) )
// Cleanup
err := f . FederationClientset . Services ( nsName ) . Delete ( service . Name , & metav1 . 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 , nsName ) )
} )
} )
var _ = Describe ( "with clusters" , func ( ) {
2016-06-24 00:02:49 +00:00
BeforeEach ( func ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
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
2017-04-04 16:21:38 +00:00
clusters = f . GetRegisteredClusters ( )
2016-06-23 20:12:44 +00:00
} )
2016-06-13 10:00:49 +00:00
2017-02-14 07:19:56 +00:00
Describe ( "Federated Service" , func ( ) {
2016-09-16 03:31:00 +00:00
var (
service * v1 . Service
nsName string
)
2016-06-24 00:02:49 +00:00
BeforeEach ( func ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
2017-02-14 07:19:56 +00:00
nsName = f . FederationNamespace . Name
2016-06-24 00:02:49 +00:00
} )
2016-06-07 09:16:18 +00:00
2016-06-24 00:02:49 +00:00
AfterEach ( func ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
2016-09-16 03:31:00 +00:00
if service != nil {
By ( fmt . Sprintf ( "Deleting service shards and their provider resources in underlying clusters for service %q in namespace %q" , service . Name , nsName ) )
cleanupServiceShardsAndProviderResources ( nsName , service , clusters )
service = nil
nsName = ""
}
2016-06-24 00:02:49 +00:00
} )
2016-06-07 09:16:18 +00:00
2017-02-10 17:31:56 +00:00
It ( "should create and update matching services in underlying clusters" , func ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
service = createServiceOrFail ( f . FederationClientset , nsName , FederatedServiceName )
2016-06-24 00:02:49 +00:00
defer func ( ) { // Cleanup
2016-08-22 17:48:43 +00:00
By ( fmt . Sprintf ( "Deleting service %q in namespace %q" , service . Name , nsName ) )
2017-01-24 15:38:21 +00:00
err := f . FederationClientset . Services ( nsName ) . Delete ( service . Name , & metav1 . DeleteOptions { } )
2016-08-22 17:48:43 +00:00
framework . ExpectNoError ( err , "Error deleting service %q in namespace %q" , service . Name , nsName )
2016-06-24 00:02:49 +00:00
} ( )
2017-02-10 17:31:56 +00:00
By ( fmt . Sprintf ( "Wait for service shards to be created in all clusters for service \"%s/%s\"" , nsName , service . Name ) )
2016-08-22 17:48:43 +00:00
waitForServiceShardsOrFail ( nsName , service , clusters )
2017-02-10 17:31:56 +00:00
framework . Logf ( "Successfully created and synced service \"%s/%s\" to all clusters" , nsName , service . Name )
By ( fmt . Sprintf ( "Update federated service \"%s/%s\"" , nsName , service . Name ) )
service = updateServiceOrFail ( f . FederationClientset , nsName , FederatedServiceName )
waitForServiceShardsOrFail ( nsName , service , clusters )
framework . Logf ( "Successfully updated and synced service \"%s/%s\" to clusters" , nsName , service . Name )
2016-06-24 00:02:49 +00:00
} )
2016-11-23 07:39:50 +00:00
2016-12-17 00:06:06 +00:00
It ( "should be deleted from underlying clusters when OrphanDependents is false" , func ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
2016-12-17 00:06:06 +00:00
orphanDependents := false
2017-01-11 13:23:31 +00:00
verifyCascadingDeletionForService ( f . FederationClientset , clusters , & orphanDependents , nsName )
2016-12-17 00:06:06 +00:00
By ( fmt . Sprintf ( "Verified that services were deleted from underlying clusters" ) )
} )
2016-11-23 07:39:50 +00:00
2016-12-17 00:06:06 +00:00
It ( "should not be deleted from underlying clusters when OrphanDependents is true" , func ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
2016-12-17 00:06:06 +00:00
orphanDependents := true
2017-01-11 13:23:31 +00:00
verifyCascadingDeletionForService ( f . FederationClientset , clusters , & orphanDependents , nsName )
2016-12-17 00:06:06 +00:00
By ( fmt . Sprintf ( "Verified that services were not deleted from underlying clusters" ) )
} )
2016-11-23 07:39:50 +00:00
2016-12-17 00:06:06 +00:00
It ( "should not be deleted from underlying clusters when OrphanDependents is nil" , func ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
verifyCascadingDeletionForService ( f . FederationClientset , clusters , nil , nsName )
2016-12-17 00:06:06 +00:00
By ( fmt . Sprintf ( "Verified that services were not deleted from underlying clusters" ) )
2016-11-23 07:39:50 +00:00
} )
2017-02-08 12:30:45 +00:00
It ( "should recreate service shard in underlying clusters when service shard is deleted" , func ( ) {
fedframework . SkipUnlessFederated ( f . ClientSet )
service = createServiceOrFail ( f . FederationClientset , nsName , FederatedServiceName )
defer func ( ) {
// Cleanup
By ( fmt . Sprintf ( "Deleting service %q in namespace %q" , service . Name , nsName ) )
err := f . FederationClientset . Services ( nsName ) . Delete ( service . Name , & metav1 . DeleteOptions { } )
framework . ExpectNoError ( err , "Error deleting service %q in namespace %q" , service . Name , nsName )
} ( )
By ( fmt . Sprintf ( "Wait for service shards to be created in all clusters for service \"%s/%s\"" , nsName , service . Name ) )
waitForServiceShardsOrFail ( nsName , service , clusters )
framework . Logf ( "Successfully created and synced service \"%s/%s\" to all clusters" , nsName , service . Name )
By ( fmt . Sprintf ( "Deleting a service shard in one underlying cluster" ) )
primaryClusterName := clusters [ 0 ] . Name
err := deleteServiceShard ( clusters [ 0 ] , nsName , FederatedServiceName )
framework . ExpectNoError ( err , fmt . Sprintf ( "while deleting service shard %q in cluster %q" , FederatedServiceName , primaryClusterName ) )
waitForServiceShardsOrFail ( nsName , service , clusters )
framework . Logf ( "Successfully recreated service shard \"%s/%s\" in %q cluster" , nsName , service . Name , primaryClusterName )
} )
2016-06-16 21:52:12 +00:00
} )
2017-02-01 06:26:17 +00:00
2016-06-24 00:02:49 +00:00
var _ = Describe ( "DNS" , func ( ) {
var (
2016-12-01 23:27:42 +00:00
service * v1 . Service
serviceShard * v1 . Service
2017-04-04 15:49:23 +00:00
backendPods BackendPodMap
2016-06-24 00:02:49 +00:00
)
2016-06-16 21:52:12 +00:00
BeforeEach ( func ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
2016-08-22 17:48:43 +00:00
nsName := f . FederationNamespace . Name
2016-11-24 00:26:02 +00:00
2017-04-04 15:49:23 +00:00
backendPods = createBackendPodsOrFail ( clusters , nsName , FederatedServicePodName )
2016-12-01 23:27:42 +00:00
2017-04-28 11:03:34 +00:00
service = createLBServiceOrFail ( f . FederationClientset , nsName , FederatedServiceName )
2017-07-10 17:54:48 +00:00
obj , err := scheme . Scheme . DeepCopy ( service )
2016-12-02 18:40:43 +00:00
// Cloning shouldn't fail. On the off-chance it does, we
// should shallow copy service to serviceShard before
// failing. If we don't do this we will never really
// get a chance to clean up the underlying services
// when the cloner fails for reasons not in our
// control. For example, cloner bug. That will cause
// the resources to leak, which in turn causes the
// test project to run out of quota and the entire
// suite starts failing. So we must try as hard as
// possible to cleanup the underlying services. So
// if DeepCopy fails, we are going to try with shallow
// copy as a last resort.
2016-12-01 23:27:42 +00:00
if err != nil {
serviceCopy := * service
serviceShard = & serviceCopy
framework . ExpectNoError ( err , fmt . Sprintf ( "Error in deep copying service %q" , service . Name ) )
}
var ok bool
serviceShard , ok = obj . ( * v1 . Service )
2016-12-02 18:40:43 +00:00
// Same argument as above about using shallow copy
// as a last resort.
2016-12-01 23:27:42 +00:00
if ! ok {
serviceCopy := * service
serviceShard = & serviceCopy
framework . ExpectNoError ( err , fmt . Sprintf ( "Unexpected service object copied %T" , obj ) )
}
waitForServiceShardsOrFail ( nsName , serviceShard , 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 ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
2016-08-22 17:48:43 +00:00
nsName := f . FederationNamespace . Name
2017-04-04 15:49:23 +00:00
deleteBackendPodsOrFail ( clusters , backendPods )
backendPods = nil
2016-06-29 07:34:43 +00:00
2016-06-24 00:02:49 +00:00
if service != nil {
2017-01-11 13:23:31 +00:00
deleteServiceOrFail ( f . FederationClientset , nsName , service . Name , nil )
2016-12-01 23:27:42 +00:00
service = nil
} else {
By ( "No service to delete. Service is nil" )
}
2016-09-09 21:07:42 +00:00
2016-12-01 23:27:42 +00:00
if serviceShard != nil {
2016-12-08 19:13:29 +00:00
By ( fmt . Sprintf ( "Deleting service shards and their provider resources in underlying clusters for service %q in namespace %q" , serviceShard . Name , nsName ) )
cleanupServiceShardsAndProviderResources ( nsName , serviceShard , clusters )
2016-12-01 23:27:42 +00:00
serviceShard = nil
2016-06-29 07:34:43 +00:00
} else {
2016-12-01 23:27:42 +00:00
By ( "No service shards to delete. `serviceShard` 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 ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
2016-06-16 21:52:12 +00:00
2016-08-22 17:48:43 +00:00
nsName := f . FederationNamespace . Name
2016-06-16 21:52:12 +00:00
svcDNSNames := [ ] string {
2016-06-24 00:02:49 +00:00
FederatedServiceName ,
2016-08-22 17:48:43 +00:00
fmt . Sprintf ( "%s.%s" , FederatedServiceName , nsName ) ,
fmt . Sprintf ( "%s.%s.svc.cluster.local." , FederatedServiceName , nsName ) ,
fmt . Sprintf ( "%s.%s.%s" , FederatedServiceName , nsName , federationName ) ,
fmt . Sprintf ( "%s.%s.%s.svc.cluster.local." , FederatedServiceName , nsName , federationName ) ,
2016-06-16 21:52:12 +00:00
}
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-11-23 07:39:50 +00:00
By ( "Verified that DNS rules are working as expected" )
By ( "Deleting the service to verify that DNS rules still work" )
2017-01-24 15:38:21 +00:00
err := f . FederationClientset . Services ( nsName ) . Delete ( FederatedServiceName , & metav1 . DeleteOptions { } )
2016-11-23 07:39:50 +00:00
framework . ExpectNoError ( err , "Error deleting service %q in namespace %q" , service . Name , service . Namespace )
2016-12-01 23:27:42 +00:00
// Service is deleted, unset the test block-global service variable.
service = nil
2016-11-23 07:39:50 +00:00
for i , DNSName := range svcDNSNames {
discoverService ( f , DNSName , true , "federated-service-e2e-discovery-pod-" + strconv . Itoa ( i ) )
}
By ( "Verified that deleting the service does not affect DNS records" )
2016-06-23 20:12:44 +00:00
} )
2016-06-24 00:02:49 +00:00
Context ( "non-local federated service" , func ( ) {
BeforeEach ( func ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
2016-06-16 21:52:12 +00:00
2017-04-04 16:21:38 +00:00
// Delete the backend pod from the shard which is local to the discovery pod.
primaryCluster := clusters [ 0 ]
backendPod := backendPods [ primaryCluster . Name ]
deleteOneBackendPodOrFail ( primaryCluster , backendPod )
2016-06-29 07:34:43 +00:00
2016-06-24 00:02:49 +00:00
} )
2017-03-24 23:23:27 +00:00
PIt ( "should be able to discover a non-local federated service" , func ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
2016-06-24 00:02:49 +00:00
2016-08-22 17:48:43 +00:00
nsName := f . FederationNamespace . Name
2016-06-24 00:02:49 +00:00
svcDNSNames := [ ] string {
2016-08-22 17:48:43 +00:00
fmt . Sprintf ( "%s.%s.%s" , FederatedServiceName , nsName , federationName ) ,
fmt . Sprintf ( "%s.%s.%s.svc.cluster.local." , FederatedServiceName , nsName , 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 ( ) {
2017-01-11 13:23:31 +00:00
fedframework . SkipUnlessFederated ( f . ClientSet )
2016-06-24 00:02:49 +00:00
2016-08-22 17:48:43 +00:00
nsName := f . FederationNamespace . Name
2016-06-24 00:02:49 +00:00
localSvcDNSNames := [ ] string {
FederatedServiceName ,
2016-08-22 17:48:43 +00:00
fmt . Sprintf ( "%s.%s" , FederatedServiceName , nsName ) ,
fmt . Sprintf ( "%s.%s.svc.cluster.local." , FederatedServiceName , nsName ) ,
2016-06-24 00:02:49 +00:00
}
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-12-17 00:06:06 +00:00
// verifyCascadingDeletionForService verifies that services are deleted from
// underlying clusters when orphan dependents is false and they are not
// deleted when orphan dependents is true.
2017-04-04 16:21:38 +00:00
func verifyCascadingDeletionForService ( clientset * fedclientset . Clientset , clusters fedframework . ClusterSlice , orphanDependents * bool , nsName string ) {
2016-12-17 00:06:06 +00:00
service := createServiceOrFail ( clientset , nsName , FederatedServiceName )
serviceName := service . Name
// Check subclusters if the service was created there.
By ( fmt . Sprintf ( "Waiting for service %s to be created in all underlying clusters" , serviceName ) )
err := wait . Poll ( 5 * time . Second , 2 * time . Minute , func ( ) ( bool , error ) {
for _ , cluster := range clusters {
_ , err := cluster . Core ( ) . Services ( nsName ) . Get ( serviceName , metav1 . GetOptions { } )
if err != nil {
if ! errors . IsNotFound ( err ) {
return false , err
}
return false , nil
}
}
return true , nil
} )
framework . ExpectNoError ( err , "Not all services created" )
By ( fmt . Sprintf ( "Deleting service %s" , serviceName ) )
deleteServiceOrFail ( clientset , nsName , serviceName , orphanDependents )
By ( fmt . Sprintf ( "Verifying services %s in underlying clusters" , serviceName ) )
errMessages := [ ] string { }
// service should be present in underlying clusters unless orphanDependents is false.
shouldExist := orphanDependents == nil || * orphanDependents == true
2017-04-04 16:21:38 +00:00
for _ , cluster := range clusters {
clusterName := cluster . Name
_ , err := cluster . Core ( ) . Services ( nsName ) . Get ( serviceName , metav1 . GetOptions { } )
2016-12-17 00:06:06 +00:00
if shouldExist && errors . IsNotFound ( err ) {
errMessages = append ( errMessages , fmt . Sprintf ( "unexpected NotFound error for service %s in cluster %s, expected service to exist" , serviceName , clusterName ) )
} else if ! shouldExist && ! errors . IsNotFound ( err ) {
errMessages = append ( errMessages , fmt . Sprintf ( "expected NotFound error for service %s in cluster %s, got error: %v" , serviceName , clusterName , err ) )
}
}
if len ( errMessages ) != 0 {
framework . Failf ( "%s" , strings . Join ( errMessages , "; " ) )
}
}
2017-02-10 17:31:56 +00:00
func updateServiceOrFail ( clientset * fedclientset . Clientset , namespace , name string ) * v1 . Service {
service , err := clientset . Services ( namespace ) . Get ( name , metav1 . GetOptions { } )
framework . ExpectNoError ( err , "Getting service %q in namespace %q" , name , namespace )
service . Spec . Selector [ "name" ] = "update-demo"
newService , err := clientset . Services ( namespace ) . Update ( service )
By ( fmt . Sprintf ( "Successfully updated federated service %q in namespace %q" , name , namespace ) )
return newService
}
2017-02-08 12:30:45 +00:00
func deleteServiceShard ( c * fedframework . Cluster , namespace , service string ) error {
err := c . Clientset . Services ( namespace ) . Delete ( service , & metav1 . DeleteOptions { } )
if err != nil && ! errors . IsNotFound ( err ) {
framework . Logf ( "Failed to delete service %q in namespace %q, in cluster %q" , service , namespace , c . Name )
return err
}
By ( fmt . Sprintf ( "Service %q in namespace %q in cluster %q deleted" , service , namespace , c . Name ) )
return nil
}
2017-02-13 22:58:49 +00:00
// equivalent returns true if the two services are equivalent. Fields which are expected to differ between
2017-02-10 17:31:56 +00:00
// federated services and the underlying cluster services (e.g. ClusterIP, NodePort) are ignored.
2017-05-19 12:59:07 +00:00
func equivalent ( federationService , clusterService v1 . Service ) bool {
clusterService . Spec . ClusterIP = federationService . Spec . ClusterIP
for i := range clusterService . Spec . Ports {
clusterService . Spec . Ports [ i ] . NodePort = federationService . Spec . Ports [ i ] . NodePort
2016-06-24 00:02:49 +00:00
}
2017-02-10 17:31:56 +00:00
if federationService . Name != clusterService . Name || federationService . Namespace != clusterService . Namespace {
return false
}
if ! reflect . DeepEqual ( federationService . Labels , clusterService . Labels ) && ( len ( federationService . Labels ) != 0 || len ( clusterService . Labels ) != 0 ) {
return false
}
if ! reflect . DeepEqual ( federationService . Spec , clusterService . Spec ) {
return false
}
return true
2016-06-24 00:02:49 +00:00
}