diff --git a/test/e2e/network/service.go b/test/e2e/network/service.go index 11ba96d4aa5..541569a030c 100644 --- a/test/e2e/network/service.go +++ b/test/e2e/network/service.go @@ -1865,6 +1865,68 @@ var _ = SIGDescribe("Services", func() { framework.ExpectNoError(e2eservice.VerifyServeHostnameServiceDown(cs, host, svcDisabledIP, servicePort)) }) + ginkgo.It("should implement service.kubernetes.io/headless", func() { + // this test uses e2essh.NodeSSHHosts that does not work if a Node only reports LegacyHostIP + framework.SkipUnlessProviderIs(framework.ProvidersWithSSH...) + // this test does not work if the Node does not support SSH Key + framework.SkipUnlessSSHKeyPresent() + + ns := f.Namespace.Name + numPods, servicePort := 3, defaultServeHostnameServicePort + serviceHeadlessLabels := map[string]string{v1.IsHeadlessService: ""} + + // We will create 2 services to test creating services in both states and also dynamic updates + // svcHeadless: Created with the label, will always be disabled. We create this early and + // test again late to make sure it never becomes available. + // svcHeadlessToggled: Created without the label then the label is toggled verifying reachability at each step. + + ginkgo.By("creating service-headless in namespace " + ns) + svcHeadless := getServeHostnameService("service-headless") + svcHeadless.ObjectMeta.Labels = serviceHeadlessLabels + // This should be improved, as we do not want a Headlesss Service to contain an IP... + _, svcHeadlessIP, err := e2eservice.StartServeHostnameService(cs, svcHeadless, ns, numPods) + framework.ExpectNoError(err, "failed to create replication controller with headless service: %s in the namespace: %s", svcHeadlessIP, ns) + + ginkgo.By("creating service in namespace " + ns) + svcHeadlessToggled := getServeHostnameService("service-headless-toggled") + podHeadlessToggledNames, svcHeadlessToggledIP, err := e2eservice.StartServeHostnameService(cs, svcHeadlessToggled, ns, numPods) + framework.ExpectNoError(err, "failed to create replication controller with service: %s in the namespace: %s", svcHeadlessToggledIP, ns) + + jig := e2eservice.NewTestJig(cs, svcHeadlessToggled.ObjectMeta.Name) + + hosts, err := e2essh.NodeSSHHosts(cs) + framework.ExpectNoError(err, "failed to find external/internal IPs for every node") + if len(hosts) == 0 { + e2elog.Failf("No ssh-able nodes") + } + host := hosts[0] + + ginkgo.By("verifying service is up") + framework.ExpectNoError(e2eservice.VerifyServeHostnameServiceUp(cs, ns, host, podHeadlessToggledNames, svcHeadlessToggledIP, servicePort)) + + ginkgo.By("verifying service-headless is not up") + framework.ExpectNoError(e2eservice.VerifyServeHostnameServiceDown(cs, host, svcHeadlessIP, servicePort)) + + ginkgo.By("adding service.kubernetes.io/headless label") + jig.UpdateServiceOrFail(ns, svcHeadlessToggled.ObjectMeta.Name, func(svc *v1.Service) { + svc.ObjectMeta.Labels = serviceHeadlessLabels + }) + + ginkgo.By("verifying service is not up") + framework.ExpectNoError(e2eservice.VerifyServeHostnameServiceDown(cs, host, svcHeadlessToggledIP, servicePort)) + + ginkgo.By("removing service.kubernetes.io/headless annotation") + jig.UpdateServiceOrFail(ns, svcHeadlessToggled.ObjectMeta.Name, func(svc *v1.Service) { + svc.ObjectMeta.Labels = nil + }) + + ginkgo.By("verifying service is up") + framework.ExpectNoError(e2eservice.VerifyServeHostnameServiceUp(cs, ns, host, podHeadlessToggledNames, svcHeadlessToggledIP, servicePort)) + + ginkgo.By("verifying service-headless is still not up") + framework.ExpectNoError(e2eservice.VerifyServeHostnameServiceDown(cs, host, svcHeadlessIP, servicePort)) + }) + ginkgo.It("should be rejected when no endpoints exist", func() { namespace := f.Namespace.Name serviceName := "no-pods"