diff --git a/cluster/addons/dns/skydns-rc.yaml.base b/cluster/addons/dns/skydns-rc.yaml.base index 96970c4b604..fecc1c7c1a3 100644 --- a/cluster/addons/dns/skydns-rc.yaml.base +++ b/cluster/addons/dns/skydns-rc.yaml.base @@ -44,7 +44,7 @@ spec: spec: containers: - name: kubedns - image: gcr.io/google_containers/kubedns-amd64:1.6 + image: gcr.io/google_containers/kubedns-amd64:1.7 resources: # TODO: Set memory limits when we've profiled the container for large # clusters, then set request = limit to keep this container in diff --git a/cluster/addons/dns/skydns-rc.yaml.in b/cluster/addons/dns/skydns-rc.yaml.in index 8a3e9e6884a..5133f5d1ea7 100644 --- a/cluster/addons/dns/skydns-rc.yaml.in +++ b/cluster/addons/dns/skydns-rc.yaml.in @@ -44,7 +44,7 @@ spec: spec: containers: - name: kubedns - image: gcr.io/google_containers/kubedns-amd64:1.6 + image: gcr.io/google_containers/kubedns-amd64:1.7 resources: # TODO: Set memory limits when we've profiled the container for large # clusters, then set request = limit to keep this container in diff --git a/cluster/addons/dns/skydns-rc.yaml.sed b/cluster/addons/dns/skydns-rc.yaml.sed index d7816c404c7..2e9da4d4f04 100644 --- a/cluster/addons/dns/skydns-rc.yaml.sed +++ b/cluster/addons/dns/skydns-rc.yaml.sed @@ -44,7 +44,7 @@ spec: spec: containers: - name: kubedns - image: gcr.io/google_containers/kubedns-amd64:1.6 + image: gcr.io/google_containers/kubedns-amd64:1.7 resources: # TODO: Set memory limits when we've profiled the container for large # clusters, then set request = limit to keep this container in diff --git a/test/e2e/dns.go b/test/e2e/dns.go index 534f74b2347..a4aa7ee1a4e 100644 --- a/test/e2e/dns.go +++ b/test/e2e/dns.go @@ -164,7 +164,18 @@ func createProbeCommand(namesToResolve []string, hostEntries []string, ptrLookup return probeCmd, fileNames } +// createTargetedProbeCommand returns a command line that performs a DNS lookup for a specific record type +func createTargetedProbeCommand(nameToResolve string, lookup string, fileNamePrefix string) (string, string) { + fileName := fmt.Sprintf("%s_udp@%s", fileNamePrefix, nameToResolve) + probeCmd := fmt.Sprintf("dig +short +tries=12 +norecurse %s %s > /results/%s", nameToResolve, lookup, fileName) + return probeCmd, fileName +} + func assertFilesExist(fileNames []string, fileDir string, pod *api.Pod, client *client.Client) { + assertFilesContain(fileNames, fileDir, pod, client, false, "") +} + +func assertFilesContain(fileNames []string, fileDir string, pod *api.Pod, client *client.Client, check bool, expected string) { var failed []string framework.ExpectNoError(wait.Poll(time.Second*2, time.Second*60, func() (bool, error) { @@ -173,9 +184,10 @@ func assertFilesExist(fileNames []string, fileDir string, pod *api.Pod, client * if err != nil { return false, err } + var contents []byte for _, fileName := range fileNames { if subResourceProxyAvailable { - _, err = client.Get(). + contents, err = client.Get(). Namespace(pod.Namespace). Resource("pods"). SubResource("proxy"). @@ -183,7 +195,7 @@ func assertFilesExist(fileNames []string, fileDir string, pod *api.Pod, client * Suffix(fileDir, fileName). Do().Raw() } else { - _, err = client.Get(). + contents, err = client.Get(). Prefix("proxy"). Resource("pods"). Namespace(pod.Namespace). @@ -194,6 +206,9 @@ func assertFilesExist(fileNames []string, fileDir string, pod *api.Pod, client * if err != nil { framework.Logf("Unable to read %s from pod %s: %v", fileName, pod.Name, err) failed = append(failed, fileName) + } else if check && strings.TrimSpace(string(contents)) != expected { + framework.Logf("File %s from pod %s contains '%s' instead of '%s'", fileName, pod.Name, string(contents), expected) + failed = append(failed, fileName) } } if len(failed) == 0 { @@ -226,7 +241,7 @@ func validateDNSResults(f *framework.Framework, pod *api.Pod, fileNames []string framework.Failf("Failed to get pod %s: %v", pod.Name, err) } // Try to find results for each expected name. - By("looking for the results for each expected name from probiers") + By("looking for the results for each expected name from probers") assertFilesExist(fileNames, "results", pod, f.Client) // TODO: probe from the host, too. @@ -234,6 +249,33 @@ func validateDNSResults(f *framework.Framework, pod *api.Pod, fileNames []string framework.Logf("DNS probes using %s succeeded\n", pod.Name) } +func validateTargetedProbeOutput(f *framework.Framework, pod *api.Pod, fileNames []string, value string) { + + By("submitting the pod to kubernetes") + podClient := f.Client.Pods(f.Namespace.Name) + defer func() { + By("deleting the pod") + defer GinkgoRecover() + podClient.Delete(pod.Name, api.NewDeleteOptions(0)) + }() + if _, err := podClient.Create(pod); err != nil { + framework.Failf("Failed to create %s pod: %v", pod.Name, err) + } + + framework.ExpectNoError(f.WaitForPodRunning(pod.Name)) + + By("retrieving the pod") + pod, err := podClient.Get(pod.Name) + if err != nil { + framework.Failf("Failed to get pod %s: %v", pod.Name, err) + } + // Try to find the expected value for each expected name. + By("looking for the results for each expected name from probers") + assertFilesContain(fileNames, "results", pod, f.Client, true, value) + + framework.Logf("DNS probes using %s succeeded\n", pod.Name) +} + func verifyDNSPodIsRunning(f *framework.Framework) { systemClient := f.Client.Pods(api.NamespaceSystem) By("Waiting for DNS Service to be Running") @@ -249,18 +291,23 @@ func verifyDNSPodIsRunning(f *framework.Framework) { framework.ExpectNoError(framework.WaitForPodRunningInNamespace(f.Client, &pod)) } -func createServiceSpec(serviceName string, isHeadless bool, selector map[string]string) *api.Service { +func createServiceSpec(serviceName, externalName string, isHeadless bool, selector map[string]string) *api.Service { headlessService := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: serviceName, }, Spec: api.ServiceSpec{ - Ports: []api.ServicePort{ - {Port: 80, Name: "http", Protocol: "TCP"}, - }, Selector: selector, }, } + if externalName != "" { + headlessService.Spec.Type = api.ServiceTypeExternalName + headlessService.Spec.ExternalName = externalName + } else { + headlessService.Spec.Ports = []api.ServicePort{ + {Port: 80, Name: "http", Protocol: "TCP"}, + } + } if isHeadless { headlessService.Spec.ClusterIP = "None" } @@ -295,8 +342,8 @@ var _ = framework.KubeDescribe("DNS", func() { hostEntries := []string{hostFQDN, dnsTestPodHostName} wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, hostEntries, "", "wheezy", f.Namespace.Name) jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, hostEntries, "", "jessie", f.Namespace.Name) - By("Running these commands on wheezy:" + wheezyProbeCmd + "\n") - By("Running these commands on jessie:" + jessieProbeCmd + "\n") + By("Running these commands on wheezy: " + wheezyProbeCmd + "\n") + By("Running these commands on jessie: " + jessieProbeCmd + "\n") // Run a pod which probes DNS and exposes the results by HTTP. By("creating a pod to probe DNS") @@ -310,7 +357,7 @@ var _ = framework.KubeDescribe("DNS", func() { testServiceSelector := map[string]string{ "dns-test": "true", } - headlessService := createServiceSpec(dnsTestServiceName, true, testServiceSelector) + headlessService := createServiceSpec(dnsTestServiceName, "", true, testServiceSelector) _, err := f.Client.Services(f.Namespace.Name).Create(headlessService) Expect(err).NotTo(HaveOccurred()) defer func() { @@ -319,7 +366,7 @@ var _ = framework.KubeDescribe("DNS", func() { f.Client.Services(f.Namespace.Name).Delete(headlessService.Name) }() - regularService := createServiceSpec("test-service-2", false, testServiceSelector) + regularService := createServiceSpec("test-service-2", "", false, testServiceSelector) regularService, err = f.Client.Services(f.Namespace.Name).Create(regularService) Expect(err).NotTo(HaveOccurred()) defer func() { @@ -341,8 +388,8 @@ var _ = framework.KubeDescribe("DNS", func() { wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, nil, regularService.Spec.ClusterIP, "wheezy", f.Namespace.Name) jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, nil, regularService.Spec.ClusterIP, "jessie", f.Namespace.Name) - By("Running these commands on wheezy:" + wheezyProbeCmd + "\n") - By("Running these commands on jessie:" + jessieProbeCmd + "\n") + By("Running these commands on wheezy: " + wheezyProbeCmd + "\n") + By("Running these commands on jessie: " + jessieProbeCmd + "\n") // Run a pod which probes DNS and exposes the results by HTTP. By("creating a pod to probe DNS") @@ -360,7 +407,7 @@ var _ = framework.KubeDescribe("DNS", func() { } serviceName := "dns-test-service-2" podHostname := "dns-querier-2" - headlessService := createServiceSpec(serviceName, true, testServiceSelector) + headlessService := createServiceSpec(serviceName, "", true, testServiceSelector) _, err := f.Client.Services(f.Namespace.Name).Create(headlessService) Expect(err).NotTo(HaveOccurred()) defer func() { @@ -374,8 +421,8 @@ var _ = framework.KubeDescribe("DNS", func() { namesToResolve := []string{hostFQDN} wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, hostNames, "", "wheezy", f.Namespace.Name) jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, hostNames, "", "jessie", f.Namespace.Name) - By("Running these commands on wheezy:" + wheezyProbeCmd + "\n") - By("Running these commands on jessie:" + jessieProbeCmd + "\n") + By("Running these commands on wheezy: " + wheezyProbeCmd + "\n") + By("Running these commands on jessie: " + jessieProbeCmd + "\n") // Run a pod which probes DNS and exposes the results by HTTP. By("creating a pod to probe DNS") @@ -388,4 +435,68 @@ var _ = framework.KubeDescribe("DNS", func() { validateDNSResults(f, pod1, append(wheezyFileNames, jessieFileNames...)) }) + + It("should provide DNS for ExternalName services", func() { + // Create a test ExternalName service. + By("Creating a test externalName service") + serviceName := "dns-test-service-3" + externalNameService := createServiceSpec(serviceName, "foo.example.com", false, nil) + _, err := f.Client.Services(f.Namespace.Name).Create(externalNameService) + Expect(err).NotTo(HaveOccurred()) + defer func() { + By("deleting the test externalName service") + defer GinkgoRecover() + f.Client.Services(f.Namespace.Name).Delete(externalNameService.Name) + }() + + hostFQDN := fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, f.Namespace.Name) + wheezyProbeCmd, wheezyFileName := createTargetedProbeCommand(hostFQDN, "CNAME", "wheezy") + jessieProbeCmd, jessieFileName := createTargetedProbeCommand(hostFQDN, "CNAME", "jessie") + By("Running these commands on wheezy: " + wheezyProbeCmd + "\n") + By("Running these commands on jessie: " + jessieProbeCmd + "\n") + + // Run a pod which probes DNS and exposes the results by HTTP. + By("creating a pod to probe DNS") + pod1 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, true) + + validateTargetedProbeOutput(f, pod1, []string{wheezyFileName, jessieFileName}, "foo.example.com.") + + // Test changing the externalName field + By("changing the externalName to bar.example.com") + _, err = updateService(f.Client, f.Namespace.Name, serviceName, func(s *api.Service) { + s.Spec.ExternalName = "bar.example.com" + }) + Expect(err).NotTo(HaveOccurred()) + wheezyProbeCmd, wheezyFileName = createTargetedProbeCommand(hostFQDN, "CNAME", "wheezy") + jessieProbeCmd, jessieFileName = createTargetedProbeCommand(hostFQDN, "CNAME", "jessie") + By("Running these commands on wheezy: " + wheezyProbeCmd + "\n") + By("Running these commands on jessie: " + jessieProbeCmd + "\n") + + // Run a pod which probes DNS and exposes the results by HTTP. + By("creating a second pod to probe DNS") + pod2 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, true) + + validateTargetedProbeOutput(f, pod2, []string{wheezyFileName, jessieFileName}, "bar.example.com.") + + // Test changing type from ExternalName to ClusterIP + By("changing the service to type=ClusterIP") + _, err = updateService(f.Client, f.Namespace.Name, serviceName, func(s *api.Service) { + s.Spec.Type = api.ServiceTypeClusterIP + s.Spec.ClusterIP = "127.1.2.3" + s.Spec.Ports = []api.ServicePort{ + {Port: 80, Name: "http", Protocol: "TCP"}, + } + }) + Expect(err).NotTo(HaveOccurred()) + wheezyProbeCmd, wheezyFileName = createTargetedProbeCommand(hostFQDN, "A", "wheezy") + jessieProbeCmd, jessieFileName = createTargetedProbeCommand(hostFQDN, "A", "jessie") + By("Running these commands on wheezy: " + wheezyProbeCmd + "\n") + By("Running these commands on jessie: " + jessieProbeCmd + "\n") + + // Run a pod which probes DNS and exposes the results by HTTP. + By("creating a third pod to probe DNS") + pod3 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, true) + + validateTargetedProbeOutput(f, pod3, []string{wheezyFileName, jessieFileName}, "127.1.2.3") + }) }) diff --git a/test/e2e/petset.go b/test/e2e/petset.go index 648d1ee274a..87732359f80 100644 --- a/test/e2e/petset.go +++ b/test/e2e/petset.go @@ -83,7 +83,7 @@ var _ = framework.KubeDescribe("PetSet [Slow] [Feature:PetSet]", func() { BeforeEach(func() { By("creating service " + headlessSvcName + " in namespace " + ns) - headlessService := createServiceSpec(headlessSvcName, true, labels) + headlessService := createServiceSpec(headlessSvcName, "", true, labels) _, err := c.Services(ns).Create(headlessService) Expect(err).NotTo(HaveOccurred()) })