1
1
package dns
2
2
3
3
import (
4
+ "encoding/json"
4
5
"fmt"
5
6
"hash/fnv"
6
7
"net"
@@ -10,8 +11,10 @@ import (
10
11
"github.com/golang/glog"
11
12
12
13
kapi "k8s.io/kubernetes/pkg/api"
14
+ kendpoints "k8s.io/kubernetes/pkg/api/endpoints"
13
15
"k8s.io/kubernetes/pkg/api/errors"
14
16
kclient "k8s.io/kubernetes/pkg/client/unversioned"
17
+ "k8s.io/kubernetes/pkg/util/validation"
15
18
16
19
"github.com/skynetservices/skydns/msg"
17
20
"github.com/skynetservices/skydns/server"
@@ -133,6 +136,8 @@ func (b *ServiceResolver) Records(dnsName string, exact bool) ([]msg.Service, er
133
136
endpointPrefix := base == "endpoints"
134
137
retrieveEndpoints := endpointPrefix || (len (segments ) > 3 && segments [3 ] == "_endpoints" )
135
138
139
+ includePorts := len (segments ) > 3 && hasAllPrefixedSegments (segments [3 :], "_" ) && segments [3 ] != "_endpoints"
140
+
136
141
// if has a portal IP and looking at svc
137
142
if svc .Spec .ClusterIP != kapi .ClusterIPNone && ! retrieveEndpoints {
138
143
defaultService := msg.Service {
@@ -147,41 +152,41 @@ func (b *ServiceResolver) Records(dnsName string, exact bool) ([]msg.Service, er
147
152
defaultName := buildDNSName (subdomain , defaultHash )
148
153
defaultService .Key = msg .Path (defaultName )
149
154
150
- if len (svc .Spec .Ports ) == 0 {
155
+ if len (svc .Spec .Ports ) == 0 || ! includePorts {
151
156
return []msg.Service {defaultService }, nil
152
157
}
153
158
154
159
services := []msg.Service {}
155
- if len (segments ) == 3 {
156
- for _ , p := range svc .Spec .Ports {
157
- port := p .Port
158
- if port == 0 {
159
- port = int32 (p .TargetPort .IntVal )
160
- }
161
- if port == 0 {
162
- continue
163
- }
164
- if len (p .Protocol ) == 0 {
165
- p .Protocol = kapi .ProtocolTCP
166
- }
167
- portName := p .Name
168
- if len (portName ) == 0 {
169
- portName = fmt .Sprintf ("unknown-port-%d" , port )
170
- }
171
- keyName := buildDNSName (subdomain , "_" + strings .ToLower (string (p .Protocol )), "_" + portName )
172
- services = append (services ,
173
- msg.Service {
174
- Host : svc .Spec .ClusterIP ,
175
- Port : int (port ),
176
-
177
- Priority : 10 ,
178
- Weight : 10 ,
179
- Ttl : 30 ,
180
-
181
- Key : msg .Path (keyName ),
182
- },
183
- )
160
+ protocolMatch , portMatch := segments [3 ], "*"
161
+ if len (segments ) > 4 {
162
+ portMatch = segments [4 ]
163
+ }
164
+ for _ , p := range svc .Spec .Ports {
165
+ portSegment , protocolSegment , ok := matchesPortAndProtocol (p .Name , string (p .Protocol ), portMatch , protocolMatch )
166
+ if ! ok {
167
+ continue
168
+ }
169
+
170
+ port := p .Port
171
+ if port == 0 {
172
+ port = int32 (p .TargetPort .IntVal )
184
173
}
174
+
175
+ keyName := buildDNSName (defaultName , protocolSegment , portSegment )
176
+ services = append (services ,
177
+ msg.Service {
178
+ Host : svc .Spec .ClusterIP ,
179
+ Port : int (port ),
180
+
181
+ Priority : 10 ,
182
+ Weight : 10 ,
183
+ Ttl : 30 ,
184
+
185
+ TargetStrip : 2 ,
186
+
187
+ Key : msg .Path (keyName ),
188
+ },
189
+ )
185
190
}
186
191
if len (services ) == 0 {
187
192
services = append (services , defaultService )
@@ -196,6 +201,14 @@ func (b *ServiceResolver) Records(dnsName string, exact bool) ([]msg.Service, er
196
201
return nil , errNoSuchName
197
202
}
198
203
204
+ hostnameMappings := noHostnameMappings
205
+ if savedHostnames := endpoints .Annotations [kendpoints .PodHostnamesAnnotation ]; len (savedHostnames ) > 0 {
206
+ mapped := make (map [string ]kendpoints.HostRecord )
207
+ if err = json .Unmarshal ([]byte (savedHostnames ), & mapped ); err == nil {
208
+ hostnameMappings = mapped
209
+ }
210
+ }
211
+
199
212
services := make ([]msg.Service , 0 , len (endpoints .Subsets )* 4 )
200
213
for _ , s := range endpoints .Subsets {
201
214
for _ , a := range s .Addresses {
@@ -207,38 +220,43 @@ func (b *ServiceResolver) Records(dnsName string, exact bool) ([]msg.Service, er
207
220
Weight : 10 ,
208
221
Ttl : 30 ,
209
222
}
210
- defaultHash := getHash (defaultService .Host )
211
- defaultName := buildDNSName (subdomain , defaultHash )
223
+ var endpointName string
224
+ if hostname , ok := getHostname (& a , hostnameMappings ); ok {
225
+ endpointName = hostname
226
+ } else {
227
+ endpointName = getHash (defaultService .Host )
228
+ }
229
+ defaultName := buildDNSName (subdomain , endpointName )
212
230
defaultService .Key = msg .Path (defaultName )
213
231
232
+ if ! includePorts {
233
+ services = append (services , defaultService )
234
+ continue
235
+ }
236
+
237
+ protocolMatch , portMatch := segments [3 ], "*"
238
+ if len (segments ) > 4 {
239
+ portMatch = segments [4 ]
240
+ }
214
241
for _ , p := range s .Ports {
215
- port := p . Port
216
- if port == 0 {
242
+ portSegment , protocolSegment , ok := matchesPortAndProtocol ( p . Name , string ( p . Protocol ), portMatch , protocolMatch )
243
+ if ! ok || p . Port == 0 {
217
244
continue
218
245
}
219
- if len (p .Protocol ) == 0 {
220
- p .Protocol = kapi .ProtocolTCP
221
- }
222
- portName := p .Name
223
- if len (portName ) == 0 {
224
- portName = fmt .Sprintf ("unknown-port-%d" , port )
225
- }
226
-
227
- keyName := buildDNSName (subdomain , "_" + strings .ToLower (string (p .Protocol )), "_" + portName , defaultHash )
246
+ keyName := buildDNSName (defaultName , protocolSegment , portSegment )
228
247
services = append (services , msg.Service {
229
248
Host : a .IP ,
230
- Port : int (port ),
249
+ Port : int (p . Port ),
231
250
232
251
Priority : 10 ,
233
252
Weight : 10 ,
234
253
Ttl : 30 ,
235
254
255
+ TargetStrip : 2 ,
256
+
236
257
Key : msg .Path (keyName ),
237
258
})
238
259
}
239
- if len (services ) == 0 {
240
- services = append (services , defaultService )
241
- }
242
260
}
243
261
}
244
262
glog .V (4 ).Infof ("Answered %s:%t with %#v" , dnsName , exact , services )
@@ -279,6 +297,21 @@ func (b *ServiceResolver) ReverseRecord(name string) (*msg.Service, error) {
279
297
// arpaSuffix is the standard suffix for PTR IP reverse lookups.
280
298
const arpaSuffix = ".in-addr.arpa."
281
299
300
+ func matchesPortAndProtocol (name , protocol , matchPortSegment , matchProtocolSegment string ) (portSegment string , protocolSegment string , match bool ) {
301
+ if len (name ) == 0 {
302
+ return "" , "" , false
303
+ }
304
+ portSegment = "_" + name
305
+ if portSegment != matchPortSegment && matchPortSegment != "*" {
306
+ return "" , "" , false
307
+ }
308
+ protocolSegment = "_" + strings .ToLower (string (protocol ))
309
+ if protocolSegment != matchProtocolSegment && matchProtocolSegment != "*" {
310
+ return "" , "" , false
311
+ }
312
+ return portSegment , protocolSegment , true
313
+ }
314
+
282
315
// extractIP turns a standard PTR reverse record lookup name
283
316
// into an IP address
284
317
func extractIP (reverseName string ) (string , bool ) {
@@ -309,6 +342,17 @@ func buildDNSName(labels ...string) string {
309
342
return res
310
343
}
311
344
345
+ // getHostname returns true if the provided address has a hostname, or false otherwise.
346
+ func getHostname (address * kapi.EndpointAddress , podHostnames map [string ]kendpoints.HostRecord ) (string , bool ) {
347
+ if len (address .Hostname ) > 0 {
348
+ return address .Hostname , true
349
+ }
350
+ if hostRecord , exists := podHostnames [address .IP ]; exists && len (validation .IsDNS1123Label (hostRecord .HostName )) == 0 {
351
+ return hostRecord .HostName , true
352
+ }
353
+ return "" , false
354
+ }
355
+
312
356
// return a hash for the key name
313
357
func getHash (text string ) string {
314
358
h := fnv .New32a ()
@@ -321,3 +365,15 @@ func getHash(text string) string {
321
365
func convertDashIPToIP (ip string ) string {
322
366
return strings .Join (strings .Split (ip , "-" ), "." )
323
367
}
368
+
369
+ // hasAllPrefixedSegments returns true if all provided segments have the given prefix.
370
+ func hasAllPrefixedSegments (segments []string , prefix string ) bool {
371
+ for _ , s := range segments {
372
+ if ! strings .HasPrefix (s , prefix ) {
373
+ return false
374
+ }
375
+ }
376
+ return true
377
+ }
378
+
379
+ var noHostnameMappings = map [string ]kendpoints.HostRecord {}
0 commit comments