1
16
17 package network
18
19 import (
20 "context"
21 "fmt"
22 "path/filepath"
23 "strings"
24 "time"
25
26 "github.com/onsi/ginkgo/v2"
27
28 v1 "k8s.io/api/core/v1"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 "k8s.io/apimachinery/pkg/labels"
31 "k8s.io/apimachinery/pkg/util/wait"
32 clientset "k8s.io/client-go/kubernetes"
33 api "k8s.io/kubernetes/pkg/apis/core"
34 "k8s.io/kubernetes/test/e2e/feature"
35 "k8s.io/kubernetes/test/e2e/framework"
36 e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"
37 e2enetwork "k8s.io/kubernetes/test/e2e/framework/network"
38 e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
39 e2eoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"
40 e2eresource "k8s.io/kubernetes/test/e2e/framework/resource"
41 e2eservice "k8s.io/kubernetes/test/e2e/framework/service"
42 e2etestfiles "k8s.io/kubernetes/test/e2e/framework/testfiles"
43 "k8s.io/kubernetes/test/e2e/network/common"
44 admissionapi "k8s.io/pod-security-admission/api"
45 )
46
47 const (
48 dnsReadyTimeout = time.Minute
49
50
51 RespondingTimeout = 2 * time.Minute
52 )
53
54 const queryDNSPythonTemplate string = `
55 import socket
56 try:
57 socket.gethostbyname('%s')
58 print('ok')
59 except:
60 print('err')`
61
62 var _ = common.SIGDescribe("ClusterDns", feature.Example, func() {
63 f := framework.NewDefaultFramework("cluster-dns")
64 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
65
66 var c clientset.Interface
67 ginkgo.BeforeEach(func() {
68 c = f.ClientSet
69 })
70
71 read := func(file string) string {
72 data, err := e2etestfiles.Read(file)
73 if err != nil {
74 framework.Fail(err.Error())
75 }
76 return string(data)
77 }
78
79 ginkgo.It("should create pod that uses dns", func(ctx context.Context) {
80
81
82
83
84
85 backendName := "dns-backend"
86 frontendName := "dns-frontend"
87 clusterDnsPath := "test/e2e/testing-manifests/cluster-dns"
88 podOutput := "Hello World!"
89
90
91
92 namespaces := []*v1.Namespace{nil, nil}
93 for i := range namespaces {
94 var err error
95 namespaceName := fmt.Sprintf("dnsexample%d", i)
96 namespaces[i], err = f.CreateNamespace(ctx, namespaceName, nil)
97 framework.ExpectNoError(err, "failed to create namespace: %s", namespaceName)
98 }
99
100 for _, ns := range namespaces {
101 e2ekubectl.RunKubectlOrDieInput(ns.Name, read(filepath.Join(clusterDnsPath, "dns-backend-rc.yaml")), "create", "-f", "-")
102 }
103
104 for _, ns := range namespaces {
105 e2ekubectl.RunKubectlOrDieInput(ns.Name, read(filepath.Join(clusterDnsPath, "dns-backend-service.yaml")), "create", "-f", "-")
106 }
107
108
109 for _, ns := range namespaces {
110 e2eresource.WaitForControlledPodsRunning(ctx, c, ns.Name, backendName, api.Kind("ReplicationController"))
111 framework.ExpectNoError(e2enetwork.WaitForService(ctx, c, ns.Name, backendName, true, framework.Poll, framework.ServiceStartTimeout))
112 }
113
114
115 for _, ns := range namespaces {
116 label := labels.SelectorFromSet(labels.Set(map[string]string{"name": backendName}))
117 options := metav1.ListOptions{LabelSelector: label.String()}
118 pods, err := c.CoreV1().Pods(ns.Name).List(ctx, options)
119 framework.ExpectNoError(err, "failed to list pods in namespace: %s", ns.Name)
120 err = e2epod.WaitForPodsResponding(ctx, c, ns.Name, backendName, false, 0, pods)
121 framework.ExpectNoError(err, "waiting for all pods to respond")
122 framework.Logf("found %d backend pods responding in namespace %s", len(pods.Items), ns.Name)
123
124 err = waitForServiceResponding(ctx, c, ns.Name, backendName)
125 framework.ExpectNoError(err, "waiting for the service to respond")
126 }
127
128
129
130
131
132
133
134
135
136 label := labels.SelectorFromSet(labels.Set(map[string]string{"name": backendName}))
137 options := metav1.ListOptions{LabelSelector: label.String()}
138 pods, err := c.CoreV1().Pods(namespaces[0].Name).List(ctx, options)
139
140 if err != nil || pods == nil || len(pods.Items) == 0 {
141 framework.Failf("no running pods found")
142 }
143 podName := pods.Items[0].Name
144
145 queryDNS := fmt.Sprintf(queryDNSPythonTemplate, backendName+"."+namespaces[0].Name)
146 _, err = e2eoutput.LookForStringInPodExec(namespaces[0].Name, podName, []string{"python", "-c", queryDNS}, "ok", dnsReadyTimeout)
147 framework.ExpectNoError(err, "waiting for output from pod exec")
148
149 updatedPodYaml := strings.Replace(read(filepath.Join(clusterDnsPath, "dns-frontend-pod.yaml")), fmt.Sprintf("dns-backend.development.svc.%s", framework.TestContext.ClusterDNSDomain), fmt.Sprintf("dns-backend.%s.svc.%s", namespaces[0].Name, framework.TestContext.ClusterDNSDomain), 1)
150
151
152 for _, ns := range namespaces {
153 e2ekubectl.RunKubectlOrDieInput(ns.Name, updatedPodYaml, "create", "-f", "-")
154 }
155
156
157
158 for _, ns := range namespaces {
159 err := e2epod.WaitForPodNotPending(ctx, c, ns.Name, frontendName)
160 framework.ExpectNoError(err)
161 }
162
163
164 for _, ns := range namespaces {
165 _, err := e2eoutput.LookForStringInLog(ns.Name, frontendName, frontendName, podOutput, framework.PodStartTimeout)
166 framework.ExpectNoError(err, "pod %s failed to print result in logs", frontendName)
167 }
168 })
169 })
170
171
172 func waitForServiceResponding(ctx context.Context, c clientset.Interface, ns, name string) error {
173 ginkgo.By(fmt.Sprintf("trying to dial the service %s.%s via the proxy", ns, name))
174
175 return wait.PollUntilContextTimeout(ctx, framework.Poll, RespondingTimeout, true, func(ctx context.Context) (done bool, err error) {
176 proxyRequest, errProxy := e2eservice.GetServicesProxyRequest(c, c.CoreV1().RESTClient().Get())
177 if errProxy != nil {
178 framework.Logf("Failed to get services proxy request: %v:", errProxy)
179 return false, nil
180 }
181
182 ctx, cancel := context.WithTimeout(ctx, framework.SingleCallTimeout)
183 defer cancel()
184
185 body, err := proxyRequest.Namespace(ns).
186 Name(name).
187 Do(ctx).
188 Raw()
189 if err != nil {
190 if ctx.Err() != nil {
191 framework.Failf("Failed to GET from service %s: %v", name, err)
192 return true, err
193 }
194 framework.Logf("Failed to GET from service %s: %v:", name, err)
195 return false, nil
196 }
197 got := string(body)
198 if len(got) == 0 {
199 framework.Logf("Service %s: expected non-empty response", name)
200 return false, err
201 }
202 framework.Logf("Service %s: found nonempty answer: %s", name, got)
203 return true, nil
204 })
205 }
206
View as plain text