mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-09 21:21:14 +00:00
SRV record support
This commit is contained in:
313
test/e2e/dns.go
313
test/e2e/dns.go
@@ -18,14 +18,15 @@ package e2e
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/wait"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -36,6 +37,108 @@ var dnsServiceLableSelector = labels.Set{
|
||||
"kubernetes.io/cluster-service": "true",
|
||||
}.AsSelector()
|
||||
|
||||
func createDNSPod(namespace, probeCmd string) *api.Pod {
|
||||
pod := &api.Pod{
|
||||
TypeMeta: api.TypeMeta{
|
||||
Kind: "Pod",
|
||||
APIVersion: latest.Version,
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "dns-test-" + string(util.NewUUID()),
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{
|
||||
{
|
||||
Name: "results",
|
||||
VolumeSource: api.VolumeSource{
|
||||
EmptyDir: &api.EmptyDirVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{
|
||||
// TODO: Consider scraping logs instead of running a webserver.
|
||||
{
|
||||
Name: "webserver",
|
||||
Image: "gcr.io/google_containers/test-webserver",
|
||||
Ports: []api.ContainerPort{
|
||||
{
|
||||
Name: "http",
|
||||
ContainerPort: 80,
|
||||
},
|
||||
},
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{
|
||||
Name: "results",
|
||||
MountPath: "/results",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "querier",
|
||||
Image: "gcr.io/google_containers/dnsutils",
|
||||
Command: []string{"sh", "-c", probeCmd},
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{
|
||||
Name: "results",
|
||||
MountPath: "/results",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return pod
|
||||
}
|
||||
|
||||
func createProbeCommand(namesToResolve []string) (string, []string) {
|
||||
fileNames := make([]string, 0, len(namesToResolve)*2)
|
||||
probeCmd := "for i in `seq 1 600`; do "
|
||||
for _, name := range namesToResolve {
|
||||
// Resolve by TCP and UDP DNS. Use $$(...) because $(...) is
|
||||
// expanded by kubernetes (though this won't expand so should
|
||||
// remain a literal, safe > sorry).
|
||||
lookup := "A"
|
||||
if strings.HasPrefix(name, "_") {
|
||||
lookup = "SRV"
|
||||
}
|
||||
fileName := fmt.Sprintf("udp@%s", name)
|
||||
fileNames = append(fileNames, fileName)
|
||||
probeCmd += fmt.Sprintf(`test -n "$$(dig +notcp +noall +answer +search %s %s)" && echo OK > /results/%s;`, name, lookup, fileName)
|
||||
fileName = fmt.Sprintf("tcp@%s", name)
|
||||
fileNames = append(fileNames, fileName)
|
||||
probeCmd += fmt.Sprintf(`test -n "$$(dig +tcp +noall +answer +search %s %s)" && echo OK > /results/%s;`, name, lookup, fileName)
|
||||
}
|
||||
probeCmd += "sleep 1; done"
|
||||
return probeCmd, fileNames
|
||||
}
|
||||
|
||||
func assertFilesExist(fileNames []string, fileDir string, pod *api.Pod, client *client.Client) {
|
||||
var failed []string
|
||||
|
||||
expectNoError(wait.Poll(time.Second*2, time.Second*60, func() (bool, error) {
|
||||
failed = []string{}
|
||||
for _, fileName := range fileNames {
|
||||
_, err := client.Get().
|
||||
Prefix("proxy").
|
||||
Resource("pods").
|
||||
Namespace(pod.Namespace).
|
||||
Name(pod.Name).
|
||||
Suffix(fileDir, fileName).
|
||||
Do().Raw()
|
||||
if err != nil {
|
||||
failed = append(failed, fileName)
|
||||
}
|
||||
}
|
||||
if len(failed) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
Logf("Lookups using %s failed for: %v\n", pod.Name, failed)
|
||||
return false, nil
|
||||
}))
|
||||
Expect(len(failed)).To(Equal(0))
|
||||
}
|
||||
|
||||
var _ = Describe("DNS", func() {
|
||||
f := NewFramework("dns")
|
||||
|
||||
@@ -71,62 +174,11 @@ var _ = Describe("DNS", func() {
|
||||
namesToResolve = append(namesToResolve, "metadata")
|
||||
}
|
||||
|
||||
probeCmd := "for i in `seq 1 600`; do "
|
||||
for _, name := range namesToResolve {
|
||||
// Resolve by TCP and UDP DNS. Use $$(...) because $(...) is
|
||||
// expanded by kubernetes (though this won't expand so should
|
||||
// remain a literal, safe > sorry).
|
||||
probeCmd += fmt.Sprintf(`test -n "$$(dig +notcp +noall +answer +search %s)" && echo OK > /results/udp@%s;`, name, name)
|
||||
probeCmd += fmt.Sprintf(`test -n "$$(dig +tcp +noall +answer +search %s)" && echo OK > /results/tcp@%s;`, name, name)
|
||||
}
|
||||
probeCmd += "sleep 1; done"
|
||||
probeCmd, fileNames := createProbeCommand(namesToResolve)
|
||||
|
||||
// Run a pod which probes DNS and exposes the results by HTTP.
|
||||
By("creating a pod to probe DNS")
|
||||
pod := &api.Pod{
|
||||
TypeMeta: api.TypeMeta{
|
||||
Kind: "Pod",
|
||||
APIVersion: latest.Version,
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "dns-test-" + string(util.NewUUID()),
|
||||
Namespace: f.Namespace.Name,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{
|
||||
{
|
||||
Name: "results",
|
||||
VolumeSource: api.VolumeSource{
|
||||
EmptyDir: &api.EmptyDirVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{
|
||||
// TODO: Consider scraping logs instead of running a webserver.
|
||||
{
|
||||
Name: "webserver",
|
||||
Image: "gcr.io/google_containers/test-webserver",
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{
|
||||
Name: "results",
|
||||
MountPath: "/results",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "querier",
|
||||
Image: "gcr.io/google_containers/dnsutils",
|
||||
Command: []string{"sh", "-c", probeCmd},
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{
|
||||
Name: "results",
|
||||
MountPath: "/results",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
pod := createDNSPod(f.Namespace.Name, probeCmd)
|
||||
|
||||
By("submitting the pod to kubernetes")
|
||||
podClient = f.Client.Pods(f.Namespace.Name)
|
||||
@@ -149,38 +201,13 @@ var _ = Describe("DNS", func() {
|
||||
|
||||
// Try to find results for each expected name.
|
||||
By("looking for the results for each expected name")
|
||||
var failed []string
|
||||
|
||||
expectNoError(wait.Poll(time.Second*2, time.Second*60, func() (bool, error) {
|
||||
failed = []string{}
|
||||
for _, name := range namesToResolve {
|
||||
for _, proto := range []string{"udp", "tcp"} {
|
||||
testCase := fmt.Sprintf("%s@%s", proto, name)
|
||||
_, err := f.Client.Get().
|
||||
Prefix("proxy").
|
||||
Resource("pods").
|
||||
Namespace(f.Namespace.Name).
|
||||
Name(pod.Name).
|
||||
Suffix("results", testCase).
|
||||
Do().Raw()
|
||||
if err != nil {
|
||||
failed = append(failed, testCase)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(failed) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
Logf("Lookups using %s failed for: %v\n", pod.Name, failed)
|
||||
return false, nil
|
||||
}))
|
||||
Expect(len(failed)).To(Equal(0))
|
||||
assertFilesExist(fileNames, "results", pod, f.Client)
|
||||
|
||||
// TODO: probe from the host, too.
|
||||
|
||||
Logf("DNS probes using %s succeeded\n", pod.Name)
|
||||
})
|
||||
It("should provide DNS for headless services", func() {
|
||||
It("should provide DNS for services", func() {
|
||||
if providerIs("vagrant") {
|
||||
By("Skipping test which is broken for vagrant (See https://github.com/GoogleCloudPlatform/kubernetes/issues/3580)")
|
||||
return
|
||||
@@ -200,95 +227,66 @@ var _ = Describe("DNS", func() {
|
||||
|
||||
// Create a test headless service.
|
||||
By("Creating a test headless service")
|
||||
testServiceName := "test-service"
|
||||
testServiceSelector := map[string]string{
|
||||
"dns-test": "true",
|
||||
}
|
||||
svc := &api.Service{
|
||||
headlessService := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: testServiceName,
|
||||
Name: "test-service",
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
ClusterIP: "None",
|
||||
Ports: []api.ServicePort{
|
||||
{Port: 80},
|
||||
{Port: 80, Name: "http", Protocol: "tcp"},
|
||||
},
|
||||
Selector: testServiceSelector,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = f.Client.Services(f.Namespace.Name).Create(svc)
|
||||
_, err = f.Client.Services(f.Namespace.Name).Create(headlessService)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
defer func() {
|
||||
By("deleting the test headless service")
|
||||
defer GinkgoRecover()
|
||||
f.Client.Services(f.Namespace.Name).Delete(svc.Name)
|
||||
f.Client.Services(f.Namespace.Name).Delete(headlessService.Name)
|
||||
}()
|
||||
|
||||
regularService := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "test-service-2",
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Port: 80, Name: "http", Protocol: "tcp"},
|
||||
},
|
||||
Selector: testServiceSelector,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = f.Client.Services(f.Namespace.Name).Create(regularService)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
defer func() {
|
||||
By("deleting the test service")
|
||||
defer GinkgoRecover()
|
||||
f.Client.Services(f.Namespace.Name).Delete(regularService.Name)
|
||||
}()
|
||||
|
||||
// All the names we need to be able to resolve.
|
||||
// TODO: Create more endpoints and ensure that multiple A records are returned
|
||||
// for headless service.
|
||||
namesToResolve := []string{
|
||||
fmt.Sprintf("%s", testServiceName),
|
||||
fmt.Sprintf("%s.%s", testServiceName, f.Namespace.Name),
|
||||
fmt.Sprintf("%s.%s.svc", testServiceName, f.Namespace.Name),
|
||||
fmt.Sprintf("%s", headlessService.Name),
|
||||
fmt.Sprintf("%s.%s", headlessService.Name, f.Namespace.Name),
|
||||
fmt.Sprintf("%s.%s.svc", headlessService.Name, f.Namespace.Name),
|
||||
fmt.Sprintf("_http._tcp.%s.%s.svc", headlessService.Name, f.Namespace.Name),
|
||||
fmt.Sprintf("_http._tcp.%s.%s.svc", regularService.Name, f.Namespace.Name),
|
||||
}
|
||||
|
||||
probeCmd := "for i in `seq 1 600`; do "
|
||||
for _, name := range namesToResolve {
|
||||
// Resolve by TCP and UDP DNS. Use $$(...) because $(...) is
|
||||
// expanded by kubernetes (though this won't expand so should
|
||||
// remain a literal, safe > sorry).
|
||||
probeCmd += fmt.Sprintf(`test -n "$$(dig +notcp +noall +answer +search %s)" && echo OK > /results/udp@%s;`, name, name)
|
||||
probeCmd += fmt.Sprintf(`test -n "$$(dig +tcp +noall +answer +search %s)" && echo OK > /results/tcp@%s;`, name, name)
|
||||
}
|
||||
probeCmd += "sleep 1; done"
|
||||
probeCmd, fileNames := createProbeCommand(namesToResolve)
|
||||
// Run a pod which probes DNS and exposes the results by HTTP.
|
||||
By("creating a pod to probe DNS")
|
||||
pod := &api.Pod{
|
||||
TypeMeta: api.TypeMeta{
|
||||
Kind: "Pod",
|
||||
APIVersion: latest.Version,
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "dns-test",
|
||||
Labels: testServiceSelector,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Volumes: []api.Volume{
|
||||
{
|
||||
Name: "results",
|
||||
VolumeSource: api.VolumeSource{
|
||||
EmptyDir: &api.EmptyDirVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []api.Container{
|
||||
// TODO: Consider scraping logs instead of running a webserver.
|
||||
{
|
||||
Name: "webserver",
|
||||
Image: "gcr.io/google_containers/test-webserver",
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{
|
||||
Name: "results",
|
||||
MountPath: "/results",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "querier",
|
||||
Image: "gcr.io/google_containers/dnsutils",
|
||||
Command: []string{"sh", "-c", probeCmd},
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{
|
||||
Name: "results",
|
||||
MountPath: "/results",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
pod := createDNSPod(f.Namespace.Name, probeCmd)
|
||||
pod.ObjectMeta.Labels = testServiceSelector
|
||||
|
||||
By("submitting the pod to kubernetes")
|
||||
podClient = f.Client.Pods(f.Namespace.Name)
|
||||
@@ -311,32 +309,7 @@ var _ = Describe("DNS", func() {
|
||||
|
||||
// Try to find results for each expected name.
|
||||
By("looking for the results for each expected name")
|
||||
var failed []string
|
||||
|
||||
expectNoError(wait.Poll(time.Second*2, time.Second*60, func() (bool, error) {
|
||||
failed = []string{}
|
||||
for _, name := range namesToResolve {
|
||||
for _, proto := range []string{"udp", "tcp"} {
|
||||
testCase := fmt.Sprintf("%s@%s", proto, name)
|
||||
_, err := f.Client.Get().
|
||||
Prefix("proxy").
|
||||
Resource("pods").
|
||||
Namespace(f.Namespace.Name).
|
||||
Name(pod.Name).
|
||||
Suffix("results", testCase).
|
||||
Do().Raw()
|
||||
if err != nil {
|
||||
failed = append(failed, testCase)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(failed) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
Logf("Lookups using %s failed for: %v\n", pod.Name, failed)
|
||||
return false, nil
|
||||
}))
|
||||
Expect(len(failed)).To(Equal(0))
|
||||
assertFilesExist(fileNames, "results", pod, f.Client)
|
||||
|
||||
// TODO: probe from the host, too.
|
||||
|
||||
|
Reference in New Issue
Block a user