@@ -4,14 +4,57 @@ import (
4
4
"context"
5
5
"math/rand"
6
6
"net"
7
+ "time"
7
8
9
+ "github.com/coredns/coredns/plugin"
8
10
"github.com/coredns/coredns/request"
9
11
"github.com/miekg/dns"
10
12
api "k8s.io/api/core/v1"
11
13
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
12
14
)
13
15
14
- func (k Kubernetes ) chaosDNS (ctx context.Context , w dns.ResponseWriter , r * dns.Msg , state request.Request ) (int , error ) {
16
+ const (
17
+ // ScopeInner means chaos only works on the inner host in Kubernetes cluster
18
+ ScopeInner = "INNER"
19
+ // ScopeOuter means chaos only works on the outer host of Kubernetes cluster
20
+ ScopeOuter = "OUTER"
21
+ // ScopeAll means chaos works on all host
22
+ ScopeAll = "ALL"
23
+
24
+ // ModeError means return error for DNS request
25
+ ModeError = "ERROR"
26
+ // ModeRandom means return random IP for DNS request
27
+ ModeRandom = "RANDOM"
28
+ )
29
+
30
+ // PodInfo saves some information for pod
31
+ type PodInfo struct {
32
+ Namespace string
33
+ Name string
34
+ Mode string
35
+ Scope string
36
+ IP string
37
+ LastUpdateTime time.Time
38
+ }
39
+
40
+ // IsOverdue ...
41
+ func (p * PodInfo ) IsOverdue () bool {
42
+ // if the pod's IP is not updated greater than 10 seconds, will treate it as overdue
43
+ // and need to update it
44
+ if time .Since (p .LastUpdateTime ) > time .Duration (time .Second * 10 ) {
45
+ return true
46
+ }
47
+
48
+ return false
49
+ }
50
+
51
+ func (k Kubernetes ) chaosDNS (ctx context.Context , w dns.ResponseWriter , r * dns.Msg , state request.Request , podInfo * PodInfo ) (int , error ) {
52
+ if podInfo .Mode == ModeError {
53
+ return dns .RcodeServerFailure , nil
54
+ }
55
+
56
+ // return random IP
57
+
15
58
answers := []dns.RR {}
16
59
qname := state .Name ()
17
60
@@ -22,6 +65,7 @@ func (k Kubernetes) chaosDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M
22
65
log .Infof ("dns.TypeA %v" , ips )
23
66
answers = a (qname , 10 , ips )
24
67
case dns .TypeAAAA :
68
+ // TODO: return random IP
25
69
ips := []net.IP {net.IP {0x20 , 0x1 , 0xd , 0xb8 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0x23 , 0 , 0x12 , 0 , 0x1 }}
26
70
log .Infof ("dns.TypeAAAA %v" , ips )
27
71
answers = aaaa (qname , 10 , ips )
@@ -77,35 +121,68 @@ func aaaa(zone string, ttl uint32, ips []net.IP) []dns.RR {
77
121
return answers
78
122
}
79
123
80
- func (k Kubernetes ) getChaosMode ( pod * api. Pod ) string {
124
+ func (k Kubernetes ) getChaosPod ( ip string ) ( * PodInfo , error ) {
81
125
k .RLock ()
82
- defer k .RUnlock ()
83
126
84
- if pod == nil {
85
- return ""
127
+ podInfo := k .ipPodMap [ip ]
128
+ if podInfo == nil {
129
+ k .RUnlock ()
130
+ return nil , nil
86
131
}
87
132
88
- if _ , ok := k .podChaosMap [pod .Namespace ]; ok {
89
- return k.podChaosMap [pod.Namespace ][pod.Name ]
133
+ if podInfo .IsOverdue () {
134
+ k .RUnlock ()
135
+
136
+ v1Pod , err := k .getPodFromCluster (podInfo .Namespace , podInfo .Name )
137
+ if err != nil {
138
+ return nil , err
139
+ }
140
+
141
+ if v1Pod .Status .PodIP != podInfo .IP {
142
+ k .Lock ()
143
+ podInfo .IP = v1Pod .Status .PodIP
144
+ podInfo .LastUpdateTime = time .Now ()
145
+
146
+ delete (k .ipPodMap , podInfo .IP )
147
+ k .ipPodMap [v1Pod .Status .PodIP ] = podInfo
148
+ k .Unlock ()
149
+ }
150
+
151
+ return podInfo , nil
90
152
}
91
153
92
- return ""
154
+ k .RUnlock ()
155
+ return podInfo , nil
93
156
}
94
157
95
- func (k Kubernetes ) getChaosPod () ([]api.Pod , error ) {
96
- k .RLock ()
97
- defer k .RUnlock ()
158
+ // needChaos judges weather should do chaos for the request
159
+ func (k Kubernetes ) needChaos (podInfo * PodInfo , state request.Request ) bool {
160
+ if podInfo == nil {
161
+ return false
162
+ }
98
163
99
- pods := make ([]api.Pod , 0 , 10 )
100
- for namespace := range k .podChaosMap {
101
- podList , err := k .Client .Pods (namespace ).List (context .Background (), meta.ListOptions {})
102
- if err != nil {
103
- return nil , err
164
+ if podInfo .Scope == ScopeAll {
165
+ return true
166
+ }
167
+
168
+ qname := state .QName ()
169
+ zone := plugin .Zones (k .Zones ).Matches (qname )
170
+
171
+ if zone == "" {
172
+ // is outer host
173
+ if podInfo .Scope == ScopeOuter {
174
+ return true
104
175
}
105
- for _ , pod := range podList .Items {
106
- pods = append (pods , pod )
176
+ } else {
177
+ // is inner host
178
+ if podInfo .Scope == ScopeInner {
179
+ return true
107
180
}
108
181
}
109
182
110
- return pods , nil
183
+ return false
184
+ }
185
+
186
+ func (k Kubernetes ) getPodFromCluster (namespace , name string ) (* api.Pod , error ) {
187
+ return k .Client .Pods (namespace ).Get (context .Background (), name , meta.GetOptions {})
111
188
}
0 commit comments