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"
|
|
|
|
|
2016-09-14 18:35:38 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/v1"
|
|
|
|
"k8s.io/kubernetes/test/e2e/framework"
|
|
|
|
|
2016-06-07 09:16:18 +00:00
|
|
|
. "github.com/onsi/ginkgo"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
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-23 20:12:44 +00:00
|
|
|
var FederatedServiceLabels = map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
}
|
|
|
|
|
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-07-01 22:18:34 +00:00
|
|
|
clusters = map[string]*cluster{}
|
2016-07-29 08:01:41 +00:00
|
|
|
primaryClusterName = registerClusters(clusters, UserAgentName, federationName, f)
|
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-29 08:01:41 +00:00
|
|
|
unregisterClusters(clusters, f)
|
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() {
|
2016-09-16 03:31:00 +00:00
|
|
|
var (
|
|
|
|
service *v1.Service
|
|
|
|
nsName string
|
|
|
|
)
|
|
|
|
|
2016-06-24 00:02:49 +00:00
|
|
|
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)
|
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
|
|
|
|
2016-06-24 00:02:49 +00:00
|
|
|
It("should succeed", func() {
|
|
|
|
framework.SkipUnlessFederated(f.Client)
|
2016-08-22 17:48:43 +00:00
|
|
|
|
2016-09-16 03:31:00 +00:00
|
|
|
nsName = f.FederationNamespace.Name
|
2016-09-02 18:57:44 +00:00
|
|
|
service = createServiceOrFail(f.FederationClientset_1_5, nsName, FederatedServiceName)
|
2016-08-22 17:48:43 +00:00
|
|
|
By(fmt.Sprintf("Creation of service %q in namespace %q succeeded. Deleting service.", service.Name, nsName))
|
2016-09-09 21:07:42 +00:00
|
|
|
|
2016-06-24 00:02:49 +00:00
|
|
|
// Cleanup
|
2016-09-02 18:57:44 +00:00
|
|
|
err := f.FederationClientset_1_5.Services(nsName).Delete(service.Name, &v1.DeleteOptions{})
|
2016-06-24 00:02:49 +00:00
|
|
|
framework.ExpectNoError(err, "Error deleting service %q in namespace %q", service.Name, service.Namespace)
|
2016-08-22 17:48:43 +00:00
|
|
|
By(fmt.Sprintf("Deletion of service %q in namespace %q succeeded.", service.Name, nsName))
|
2016-06-24 00:02:49 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
It("should create matching services in underlying clusters", func() {
|
|
|
|
framework.SkipUnlessFederated(f.Client)
|
2016-08-22 17:48:43 +00:00
|
|
|
|
2016-09-16 03:31:00 +00:00
|
|
|
nsName = f.FederationNamespace.Name
|
2016-09-02 18:57:44 +00:00
|
|
|
service = createServiceOrFail(f.FederationClientset_1_5, 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))
|
2016-09-02 18:57:44 +00:00
|
|
|
err := f.FederationClientset_1_5.Services(nsName).Delete(service.Name, &v1.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
|
|
|
}()
|
2016-08-22 17:48:43 +00:00
|
|
|
waitForServiceShardsOrFail(nsName, 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-08-22 17:48:43 +00:00
|
|
|
|
|
|
|
nsName := f.FederationNamespace.Name
|
|
|
|
createBackendPodsOrFail(clusters, nsName, FederatedServicePodName)
|
2016-09-02 18:57:44 +00:00
|
|
|
service = createServiceOrFail(f.FederationClientset_1_5, nsName, FederatedServiceName)
|
2016-08-22 17:48:43 +00:00
|
|
|
waitForServiceShardsOrFail(nsName, 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-08-22 17:48:43 +00:00
|
|
|
|
|
|
|
nsName := f.FederationNamespace.Name
|
|
|
|
deleteBackendPodsOrFail(clusters, nsName)
|
2016-06-29 07:34:43 +00:00
|
|
|
|
2016-06-24 00:02:49 +00:00
|
|
|
if service != nil {
|
2016-09-02 18:57:44 +00:00
|
|
|
deleteServiceOrFail(f.FederationClientset_1_5, nsName, service.Name)
|
2016-09-09 21:07:42 +00:00
|
|
|
|
|
|
|
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)
|
2016-09-16 03:31:00 +00:00
|
|
|
|
2016-06-24 00:02:49 +00:00
|
|
|
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)
|
|
|
|
|
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-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)
|
|
|
|
|
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() {
|
|
|
|
framework.SkipUnlessFederated(f.Client)
|
|
|
|
|
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-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)
|
|
|
|
}
|