1
1
package collect
2
2
3
3
import (
4
+ "bufio"
4
5
"bytes"
5
6
"context"
6
7
"encoding/json"
7
8
"fmt"
8
9
"io"
9
- "path/filepath"
10
10
"strings"
11
11
"time"
12
12
@@ -21,7 +21,8 @@ import (
21
21
)
22
22
23
23
const (
24
- dnsUtilsImage = "registry.k8s.io/e2e-test-images/jessie-dnsutils:1.3"
24
+ dnsUtilsImage = "registry.k8s.io/e2e-test-images/agnhost:2.39"
25
+ nonResolvableDomain = "non-existent-domain"
25
26
)
26
27
27
28
type CollectDNS struct {
@@ -34,6 +35,25 @@ type CollectDNS struct {
34
35
RBACErrors
35
36
}
36
37
38
+ // DNSTroubleshootResult represents the structure of the DNS troubleshooting JSON data
39
+ type DNSTroubleshootResult struct {
40
+ KubernetesClusterIP string `json:"kubernetesClusterIP"`
41
+ PodResolvConf string `json:"podResolvConf"`
42
+ Query struct {
43
+ Kubernetes struct {
44
+ Name string `json:"name"`
45
+ Address string `json:"address"`
46
+ } `json:"kubernetes"`
47
+ NonResolvableDomain struct {
48
+ Name string `json:"name"`
49
+ Address string `json:"address"`
50
+ } `json:"nonResolvableDomain"`
51
+ } `json:"query"`
52
+ KubeDNSPods []string `json:"kubeDNSPods"`
53
+ KubeDNSService string `json:"kubeDNSService"`
54
+ KubeDNSEndpoints string `json:"kubeDNSEndpoints"`
55
+ }
56
+
37
57
func (c * CollectDNS ) Title () string {
38
58
return getCollectorName (c )
39
59
}
@@ -48,32 +68,57 @@ func (c *CollectDNS) Collect(progressChan chan<- interface{}) (CollectorResult,
48
68
defer cancel ()
49
69
50
70
sb := strings.Builder {}
71
+ dnsDebug := DNSTroubleshootResult {}
51
72
52
73
// get kubernetes Cluster IP
53
74
clusterIP , err := getKubernetesClusterIP (c .Client , ctx )
54
75
if err == nil {
55
76
sb .WriteString (fmt .Sprintf ("=== Kubernetes Cluster IP from API Server: %s\n " , clusterIP ))
77
+ dnsDebug .KubernetesClusterIP = clusterIP
56
78
} else {
57
79
sb .WriteString (fmt .Sprintf ("=== Failed to detect Kubernetes Cluster IP: %v\n " , err ))
58
80
}
59
81
60
82
// run a pod and perform DNS lookup
61
- podLog , err := troubleshootDNSFromPod (c .Client , ctx )
83
+ testDomain := c .Collector .NonResolvable
84
+ if testDomain == "" {
85
+ testDomain = nonResolvableDomain
86
+ }
87
+ dnsDebug .Query .NonResolvableDomain .Name = testDomain
88
+
89
+ image := c .Collector .Image
90
+ if image == "" {
91
+ image = dnsUtilsImage
92
+ }
93
+
94
+ podLog , err := troubleshootDNSFromPod (c .Client , ctx , testDomain , image )
62
95
if err == nil {
63
- sb .WriteString (fmt .Sprintf ("=== Test DNS resolution in pod %s: \n " , dnsUtilsImage ))
96
+ sb .WriteString (fmt .Sprintf ("=== Test DNS resolution in pod %s: \n " , image ))
64
97
sb .WriteString (podLog )
65
98
} else {
66
99
sb .WriteString (fmt .Sprintf ("=== Failed to run commands from pod: %v\n " , err ))
67
100
}
68
101
102
+ // extract DNS queries from pod log
103
+ err = extractDNSQueriesFromPodLog (podLog , & dnsDebug )
104
+ if err != nil {
105
+ sb .WriteString (fmt .Sprintf ("=== Failed to extract DNS queries from pod log: %v\n " , err ))
106
+ }
107
+
69
108
// is DNS pods running?
70
- sb .WriteString (fmt .Sprintf ("=== Running kube-dns pods: %s\n " , getRunningKubeDNSPodNames (c .Client , ctx )))
109
+ kubeDNSPods := getRunningKubeDNSPodNames (c .Client , ctx )
110
+ sb .WriteString (fmt .Sprintf ("=== Running kube-dns pods: %s\n " , kubeDNSPods ))
111
+ dnsDebug .KubeDNSPods = strings .Split (kubeDNSPods , ", " )
71
112
72
113
// is DNS service up?
73
- sb .WriteString (fmt .Sprintf ("=== Running kube-dns service: %s\n " , getKubeDNSServiceClusterIP (c .Client , ctx )))
114
+ kubeDNSService := getKubeDNSServiceClusterIP (c .Client , ctx )
115
+ sb .WriteString (fmt .Sprintf ("=== Running kube-dns service: %s\n " , kubeDNSService ))
116
+ dnsDebug .KubeDNSService = kubeDNSService
74
117
75
118
// are DNS endpoints exposed?
76
- sb .WriteString (fmt .Sprintf ("=== kube-dns endpoints: %s\n " , getKubeDNSEndpoints (c .Client , ctx )))
119
+ kubeDNSEndpoints := getKubeDNSEndpoints (c .Client , ctx )
120
+ sb .WriteString (fmt .Sprintf ("=== kube-dns endpoints: %s\n " , kubeDNSEndpoints ))
121
+ dnsDebug .KubeDNSEndpoints = kubeDNSEndpoints
77
122
78
123
// get DNS server config
79
124
coreDNSConfig , err := getCoreDNSConfig (c .Client , ctx )
@@ -89,7 +134,16 @@ func (c *CollectDNS) Collect(progressChan chan<- interface{}) (CollectorResult,
89
134
90
135
data := sb .String ()
91
136
output := NewResult ()
92
- output .SaveResult (c .BundlePath , filepath .Join ("dns" , c .Collector .CollectorName ), bytes .NewBuffer ([]byte (data )))
137
+
138
+ // save raw debug output
139
+ output .SaveResult (c .BundlePath , "dns/debug.txt" , bytes .NewBuffer ([]byte (data )))
140
+
141
+ // save structured debug output as JSON file
142
+ jsonData , err := json .Marshal (dnsDebug )
143
+ if err != nil {
144
+ return output , errors .Wrap (err , "failed to marshal DNS troubleshooting data" )
145
+ }
146
+ output .SaveResult (c .BundlePath , "dns/debug.json" , bytes .NewBuffer (jsonData ))
93
147
94
148
return output , nil
95
149
}
@@ -104,14 +158,17 @@ func getKubernetesClusterIP(client kubernetes.Interface, ctx context.Context) (s
104
158
return service .Spec .ClusterIP , nil
105
159
}
106
160
107
- func troubleshootDNSFromPod (client kubernetes.Interface , ctx context.Context ) (string , error ) {
161
+ func troubleshootDNSFromPod (client kubernetes.Interface , ctx context.Context , nonResolvableDomain string , image string ) (string , error ) {
108
162
namespace := "default"
109
- command := []string {"/bin/sh" , "-c" , `
110
- set -x
163
+ command := []string {"/bin/sh" , "-c" , fmt . Sprintf ( `
164
+ echo "=== /etc/resolv.conf ==="
111
165
cat /etc/resolv.conf
112
- nslookup -debug kubernetes
166
+ echo "=== dig kubernetes ==="
167
+ dig +search +short kubernetes
168
+ echo "=== dig non-existent-domain ==="
169
+ dig +short %s
113
170
exit 0
114
- ` }
171
+ ` , nonResolvableDomain ) }
115
172
116
173
// TODO: image pull secret?
117
174
podLabels := map [string ]string {
@@ -127,7 +184,7 @@ func troubleshootDNSFromPod(client kubernetes.Interface, ctx context.Context) (s
127
184
Containers : []corev1.Container {
128
185
{
129
186
Name : "troubleshoot-dns" ,
130
- Image : dnsUtilsImage ,
187
+ Image : image ,
131
188
Command : command ,
132
189
},
133
190
},
@@ -271,3 +328,35 @@ func getKubeDNSEndpoints(client kubernetes.Interface, ctx context.Context) strin
271
328
272
329
return strings .Join (endpointStrings , ", " )
273
330
}
331
+
332
+ func extractDNSQueriesFromPodLog (podLog string , dnsDebug * DNSTroubleshootResult ) error {
333
+ scanner := bufio .NewScanner (strings .NewReader (podLog ))
334
+
335
+ var currentSection string
336
+
337
+ for scanner .Scan () {
338
+ line := scanner .Text ()
339
+
340
+ switch {
341
+ case strings .Contains (line , "=== /etc/resolv.conf ===" ):
342
+ currentSection = "podResolvConf"
343
+ case strings .Contains (line , "=== dig kubernetes ===" ):
344
+ currentSection = "kubernetes"
345
+ case strings .Contains (line , "=== dig non-existent-domain ===" ):
346
+ currentSection = "nonResolvableDomain"
347
+ default :
348
+ switch currentSection {
349
+ case "podResolvConf" :
350
+ dnsDebug .PodResolvConf += line + "\n "
351
+ case "kubernetes" :
352
+ dnsDebug .Query .Kubernetes .Name = "kubernetes"
353
+ dnsDebug .Query .Kubernetes .Address = line
354
+ case "nonResolvableDomain" :
355
+ dnsDebug .Query .NonResolvableDomain .Address = line
356
+ }
357
+ }
358
+ }
359
+
360
+ return nil
361
+
362
+ }
0 commit comments