2017-11-14 02:26:06 +00:00
/ *
Copyright 2017 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package dns
import (
"fmt"
2018-02-22 02:32:58 +00:00
"io/ioutil"
2017-11-14 02:26:06 +00:00
"net"
2018-02-22 02:32:58 +00:00
"os"
2017-11-14 02:26:06 +00:00
"strings"
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
2017-11-19 03:46:24 +00:00
"k8s.io/apimachinery/pkg/util/sets"
utilfeature "k8s.io/apiserver/pkg/util/feature"
2017-11-14 02:26:06 +00:00
"k8s.io/client-go/tools/record"
2018-02-06 22:11:09 +00:00
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
2017-11-14 02:26:06 +00:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
2017-11-19 03:46:24 +00:00
var (
fetchEvent = func ( recorder * record . FakeRecorder ) string {
select {
case event := <- recorder . Events :
return event
default :
return ""
}
}
)
2017-11-14 02:26:06 +00:00
func TestParseResolvConf ( t * testing . T ) {
testCases := [ ] struct {
data string
nameservers [ ] string
searches [ ] string
options [ ] string
} {
{ "" , [ ] string { } , [ ] string { } , [ ] string { } } ,
{ " " , [ ] string { } , [ ] string { } , [ ] string { } } ,
{ "\n" , [ ] string { } , [ ] string { } , [ ] string { } } ,
{ "\t\n\t" , [ ] string { } , [ ] string { } , [ ] string { } } ,
{ "#comment\n" , [ ] string { } , [ ] string { } , [ ] string { } } ,
{ " #comment\n" , [ ] string { } , [ ] string { } , [ ] string { } } ,
{ "#comment\n#comment" , [ ] string { } , [ ] string { } , [ ] string { } } ,
{ "#comment\nnameserver" , [ ] string { } , [ ] string { } , [ ] string { } } ,
{ "#comment\nnameserver\nsearch" , [ ] string { } , [ ] string { } , [ ] string { } } ,
{ "nameserver 1.2.3.4" , [ ] string { "1.2.3.4" } , [ ] string { } , [ ] string { } } ,
{ " nameserver 1.2.3.4" , [ ] string { "1.2.3.4" } , [ ] string { } , [ ] string { } } ,
{ "\tnameserver 1.2.3.4" , [ ] string { "1.2.3.4" } , [ ] string { } , [ ] string { } } ,
{ "nameserver\t1.2.3.4" , [ ] string { "1.2.3.4" } , [ ] string { } , [ ] string { } } ,
{ "nameserver \t 1.2.3.4" , [ ] string { "1.2.3.4" } , [ ] string { } , [ ] string { } } ,
{ "nameserver 1.2.3.4\nnameserver 5.6.7.8" , [ ] string { "1.2.3.4" , "5.6.7.8" } , [ ] string { } , [ ] string { } } ,
{ "nameserver 1.2.3.4 #comment" , [ ] string { "1.2.3.4" } , [ ] string { } , [ ] string { } } ,
{ "search foo" , [ ] string { } , [ ] string { "foo" } , [ ] string { } } ,
{ "search foo bar" , [ ] string { } , [ ] string { "foo" , "bar" } , [ ] string { } } ,
{ "search foo bar bat\n" , [ ] string { } , [ ] string { "foo" , "bar" , "bat" } , [ ] string { } } ,
{ "search foo\nsearch bar" , [ ] string { } , [ ] string { "bar" } , [ ] string { } } ,
{ "nameserver 1.2.3.4\nsearch foo bar" , [ ] string { "1.2.3.4" } , [ ] string { "foo" , "bar" } , [ ] string { } } ,
{ "nameserver 1.2.3.4\nsearch foo\nnameserver 5.6.7.8\nsearch bar" , [ ] string { "1.2.3.4" , "5.6.7.8" } , [ ] string { "bar" } , [ ] string { } } ,
{ "#comment\nnameserver 1.2.3.4\n#comment\nsearch foo\ncomment" , [ ] string { "1.2.3.4" } , [ ] string { "foo" } , [ ] string { } } ,
{ "options ndots:5 attempts:2" , [ ] string { } , [ ] string { } , [ ] string { "ndots:5" , "attempts:2" } } ,
{ "options ndots:1\noptions ndots:5 attempts:3" , [ ] string { } , [ ] string { } , [ ] string { "ndots:5" , "attempts:3" } } ,
{ "nameserver 1.2.3.4\nsearch foo\nnameserver 5.6.7.8\nsearch bar\noptions ndots:5 attempts:4" , [ ] string { "1.2.3.4" , "5.6.7.8" } , [ ] string { "bar" } , [ ] string { "ndots:5" , "attempts:4" } } ,
}
for i , tc := range testCases {
ns , srch , opts , err := parseResolvConf ( strings . NewReader ( tc . data ) )
require . NoError ( t , err )
assert . EqualValues ( t , tc . nameservers , ns , "test case [%d]: name servers" , i )
assert . EqualValues ( t , tc . searches , srch , "test case [%d] searches" , i )
assert . EqualValues ( t , tc . options , opts , "test case [%d] options" , i )
}
}
2017-11-19 03:46:24 +00:00
func TestFormDNSSearchFitsLimits ( t * testing . T ) {
2017-11-14 02:26:06 +00:00
recorder := record . NewFakeRecorder ( 20 )
nodeRef := & v1 . ObjectReference {
Kind : "Node" ,
Name : string ( "testNode" ) ,
UID : types . UID ( "testNode" ) ,
Namespace : "" ,
}
testClusterDNSDomain := "TEST"
configurer := NewConfigurer ( recorder , nodeRef , nil , nil , testClusterDNSDomain , "" )
pod := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
UID : "" ,
Name : "test_pod" ,
Namespace : "testNS" ,
Annotations : map [ string ] string { } ,
} ,
}
testCases := [ ] struct {
hostNames [ ] string
resultSearch [ ] string
events [ ] string
} {
{
[ ] string { "testNS.svc.TEST" , "svc.TEST" , "TEST" } ,
[ ] string { "testNS.svc.TEST" , "svc.TEST" , "TEST" } ,
[ ] string { } ,
} ,
{
2017-11-19 03:46:24 +00:00
[ ] string { "testNS.svc.TEST" , "svc.TEST" , "TEST" , "AAA" , "BBB" } ,
2017-11-14 02:26:06 +00:00
[ ] string { "testNS.svc.TEST" , "svc.TEST" , "TEST" , "AAA" , "BBB" } ,
[ ] string { } ,
} ,
{
2017-11-19 03:46:24 +00:00
[ ] string { "testNS.svc.TEST" , "svc.TEST" , "TEST" , "AAA" , strings . Repeat ( "B" , 256 ) , "BBB" } ,
2017-11-14 02:26:06 +00:00
[ ] string { "testNS.svc.TEST" , "svc.TEST" , "TEST" , "AAA" } ,
2017-11-19 03:46:24 +00:00
[ ] string { "Search Line limits were exceeded, some search paths have been omitted, the applied search line is: testNS.svc.TEST svc.TEST TEST AAA" } ,
2017-11-14 02:26:06 +00:00
} ,
{
2017-11-19 03:46:24 +00:00
[ ] string { "testNS.svc.TEST" , "svc.TEST" , "TEST" , "AAA" , "BBB" , "CCC" , "DDD" } ,
2017-11-14 02:26:06 +00:00
[ ] string { "testNS.svc.TEST" , "svc.TEST" , "TEST" , "AAA" , "BBB" , "CCC" } ,
2017-11-19 03:46:24 +00:00
[ ] string { "Search Line limits were exceeded, some search paths have been omitted, the applied search line is: testNS.svc.TEST svc.TEST TEST AAA BBB CCC" } ,
2017-11-14 02:26:06 +00:00
} ,
}
for i , tc := range testCases {
2017-11-19 03:46:24 +00:00
dnsSearch := configurer . formDNSSearchFitsLimits ( tc . hostNames , pod )
2017-11-14 02:26:06 +00:00
assert . EqualValues ( t , tc . resultSearch , dnsSearch , "test [%d]" , i )
for _ , expectedEvent := range tc . events {
2017-11-19 03:46:24 +00:00
expected := fmt . Sprintf ( "%s %s %s" , v1 . EventTypeWarning , "DNSConfigForming" , expectedEvent )
2017-11-14 02:26:06 +00:00
event := fetchEvent ( recorder )
assert . Equal ( t , expected , event , "test [%d]" , i )
}
}
}
2017-11-19 03:46:24 +00:00
func TestFormDNSNameserversFitsLimits ( t * testing . T ) {
recorder := record . NewFakeRecorder ( 20 )
nodeRef := & v1 . ObjectReference {
Kind : "Node" ,
Name : string ( "testNode" ) ,
UID : types . UID ( "testNode" ) ,
Namespace : "" ,
}
testClusterDNSDomain := "TEST"
configurer := NewConfigurer ( recorder , nodeRef , nil , nil , testClusterDNSDomain , "" )
pod := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
UID : "" ,
Name : "test_pod" ,
Namespace : "testNS" ,
Annotations : map [ string ] string { } ,
} ,
}
testCases := [ ] struct {
desc string
nameservers [ ] string
expectedNameserver [ ] string
expectedEvent bool
} {
{
desc : "valid: 1 nameserver" ,
nameservers : [ ] string { "127.0.0.1" } ,
expectedNameserver : [ ] string { "127.0.0.1" } ,
expectedEvent : false ,
} ,
{
desc : "valid: 3 nameservers" ,
nameservers : [ ] string { "127.0.0.1" , "10.0.0.10" , "8.8.8.8" } ,
expectedNameserver : [ ] string { "127.0.0.1" , "10.0.0.10" , "8.8.8.8" } ,
expectedEvent : false ,
} ,
{
desc : "invalid: 4 nameservers, trimmed to 3" ,
nameservers : [ ] string { "127.0.0.1" , "10.0.0.10" , "8.8.8.8" , "1.2.3.4" } ,
expectedNameserver : [ ] string { "127.0.0.1" , "10.0.0.10" , "8.8.8.8" } ,
expectedEvent : true ,
} ,
}
for _ , tc := range testCases {
appliedNameservers := configurer . formDNSNameserversFitsLimits ( tc . nameservers , pod )
assert . EqualValues ( t , tc . expectedNameserver , appliedNameservers , tc . desc )
event := fetchEvent ( recorder )
if tc . expectedEvent && len ( event ) == 0 {
t . Errorf ( "%s: formDNSNameserversFitsLimits(%v) expected event, got no event." , tc . desc , tc . nameservers )
} else if ! tc . expectedEvent && len ( event ) > 0 {
t . Errorf ( "%s: formDNSNameserversFitsLimits(%v) expected no event, got event: %v" , tc . desc , tc . nameservers , event )
}
}
}
func TestMergeDNSOptions ( t * testing . T ) {
testOptionValue := "3"
testCases := [ ] struct {
desc string
existingDNSConfigOptions [ ] string
dnsConfigOptions [ ] v1 . PodDNSConfigOption
expectedOptions [ ] string
} {
{
desc : "Empty dnsConfigOptions" ,
existingDNSConfigOptions : [ ] string { "ndots:5" , "debug" } ,
dnsConfigOptions : nil ,
expectedOptions : [ ] string { "ndots:5" , "debug" } ,
} ,
{
desc : "No duplicated entries" ,
existingDNSConfigOptions : [ ] string { "ndots:5" , "debug" } ,
dnsConfigOptions : [ ] v1 . PodDNSConfigOption {
{ Name : "single-request" } ,
{ Name : "attempts" , Value : & testOptionValue } ,
} ,
expectedOptions : [ ] string { "ndots:5" , "debug" , "single-request" , "attempts:3" } ,
} ,
{
desc : "Overwrite duplicated entries" ,
existingDNSConfigOptions : [ ] string { "ndots:5" , "debug" } ,
dnsConfigOptions : [ ] v1 . PodDNSConfigOption {
{ Name : "ndots" , Value : & testOptionValue } ,
{ Name : "debug" } ,
{ Name : "single-request" } ,
{ Name : "attempts" , Value : & testOptionValue } ,
} ,
expectedOptions : [ ] string { "ndots:3" , "debug" , "single-request" , "attempts:3" } ,
} ,
}
for _ , tc := range testCases {
options := mergeDNSOptions ( tc . existingDNSConfigOptions , tc . dnsConfigOptions )
// Options order may be changed after conversion.
if ! sets . NewString ( options ... ) . Equal ( sets . NewString ( tc . expectedOptions ... ) ) {
t . Errorf ( "%s: mergeDNSOptions(%v, %v)=%v, want %v" , tc . desc , tc . existingDNSConfigOptions , tc . dnsConfigOptions , options , tc . expectedOptions )
}
}
}
func TestGetPodDNSType ( t * testing . T ) {
customDNSEnabled := utilfeature . DefaultFeatureGate . Enabled ( "CustomPodDNS" )
defer func ( ) {
// Restoring the old value.
if err := utilfeature . DefaultFeatureGate . Set ( fmt . Sprintf ( "CustomPodDNS=%v" , customDNSEnabled ) ) ; err != nil {
t . Errorf ( "Failed to set CustomPodDNS feature gate: %v" , err )
}
} ( )
recorder := record . NewFakeRecorder ( 20 )
nodeRef := & v1 . ObjectReference {
Kind : "Node" ,
Name : string ( "testNode" ) ,
UID : types . UID ( "testNode" ) ,
Namespace : "" ,
}
testClusterDNSDomain := "TEST"
clusterNS := "203.0.113.1"
testClusterDNS := [ ] net . IP { net . ParseIP ( clusterNS ) }
configurer := NewConfigurer ( recorder , nodeRef , nil , nil , testClusterDNSDomain , "" )
pod := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
UID : "" ,
Name : "test_pod" ,
Namespace : "testNS" ,
Annotations : map [ string ] string { } ,
} ,
}
testCases := [ ] struct {
desc string
customPodDNSFeatureGate bool
hasClusterDNS bool
hostNetwork bool
dnsPolicy v1 . DNSPolicy
expectedDNSType podDNSType
expectedError bool
} {
{
desc : "valid DNSClusterFirst without hostnetwork" ,
hasClusterDNS : true ,
dnsPolicy : v1 . DNSClusterFirst ,
expectedDNSType : podDNSCluster ,
} ,
{
desc : "valid DNSClusterFirstWithHostNet with hostnetwork" ,
hasClusterDNS : true ,
hostNetwork : true ,
dnsPolicy : v1 . DNSClusterFirstWithHostNet ,
expectedDNSType : podDNSCluster ,
} ,
{
desc : "valid DNSClusterFirstWithHostNet without hostnetwork" ,
hasClusterDNS : true ,
dnsPolicy : v1 . DNSClusterFirstWithHostNet ,
expectedDNSType : podDNSCluster ,
} ,
{
desc : "valid DNSDefault without hostnetwork" ,
dnsPolicy : v1 . DNSDefault ,
expectedDNSType : podDNSHost ,
} ,
{
desc : "valid DNSDefault with hostnetwork" ,
hostNetwork : true ,
dnsPolicy : v1 . DNSDefault ,
expectedDNSType : podDNSHost ,
} ,
{
desc : "DNSClusterFirst with hostnetwork, fallback to DNSDefault" ,
hasClusterDNS : true ,
hostNetwork : true ,
dnsPolicy : v1 . DNSClusterFirst ,
expectedDNSType : podDNSHost ,
} ,
{
desc : "valid DNSNone with feature gate" ,
customPodDNSFeatureGate : true ,
dnsPolicy : v1 . DNSNone ,
expectedDNSType : podDNSNone ,
} ,
{
desc : "DNSNone without feature gate, should return error" ,
dnsPolicy : v1 . DNSNone ,
expectedError : true ,
} ,
{
desc : "invalid DNS policy, should return error" ,
dnsPolicy : "invalidPolicy" ,
expectedError : true ,
} ,
}
for _ , tc := range testCases {
if err := utilfeature . DefaultFeatureGate . Set ( fmt . Sprintf ( "CustomPodDNS=%v" , tc . customPodDNSFeatureGate ) ) ; err != nil {
t . Errorf ( "Failed to set CustomPodDNS feature gate: %v" , err )
}
if tc . hasClusterDNS {
configurer . clusterDNS = testClusterDNS
} else {
configurer . clusterDNS = nil
}
pod . Spec . DNSPolicy = tc . dnsPolicy
pod . Spec . HostNetwork = tc . hostNetwork
resType , err := getPodDNSType ( pod )
if tc . expectedError {
if err == nil {
t . Errorf ( "%s: GetPodDNSType(%v) got no error, want error" , tc . desc , pod )
}
continue
}
if resType != tc . expectedDNSType {
t . Errorf ( "%s: GetPodDNSType(%v)=%v, want %v" , tc . desc , pod , resType , tc . expectedDNSType )
}
}
}
2017-11-17 02:44:13 +00:00
func TestGetPodDNS ( t * testing . T ) {
2017-11-14 02:26:06 +00:00
recorder := record . NewFakeRecorder ( 20 )
nodeRef := & v1 . ObjectReference {
Kind : "Node" ,
Name : string ( "testNode" ) ,
UID : types . UID ( "testNode" ) ,
Namespace : "" ,
}
clusterNS := "203.0.113.1"
testClusterDNSDomain := "kubernetes.io"
testClusterDNS := [ ] net . IP { net . ParseIP ( clusterNS ) }
configurer := NewConfigurer ( recorder , nodeRef , nil , testClusterDNS , testClusterDNSDomain , "" )
pods := newTestPods ( 4 )
pods [ 0 ] . Spec . DNSPolicy = v1 . DNSClusterFirstWithHostNet
pods [ 1 ] . Spec . DNSPolicy = v1 . DNSClusterFirst
pods [ 2 ] . Spec . DNSPolicy = v1 . DNSClusterFirst
pods [ 2 ] . Spec . HostNetwork = false
pods [ 3 ] . Spec . DNSPolicy = v1 . DNSDefault
options := make ( [ ] struct {
DNS [ ] string
DNSSearch [ ] string
} , 4 )
for i , pod := range pods {
var err error
2017-11-17 02:44:13 +00:00
dnsConfig , err := configurer . GetPodDNS ( pod )
2017-11-14 02:26:06 +00:00
if err != nil {
t . Fatalf ( "failed to generate container options: %v" , err )
}
2017-11-17 02:44:13 +00:00
options [ i ] . DNS , options [ i ] . DNSSearch = dnsConfig . Servers , dnsConfig . Searches
2017-11-14 02:26:06 +00:00
}
if len ( options [ 0 ] . DNS ) != 1 || options [ 0 ] . DNS [ 0 ] != clusterNS {
t . Errorf ( "expected nameserver %s, got %+v" , clusterNS , options [ 0 ] . DNS )
}
if len ( options [ 0 ] . DNSSearch ) == 0 || options [ 0 ] . DNSSearch [ 0 ] != ".svc." + configurer . ClusterDomain {
t . Errorf ( "expected search %s, got %+v" , ".svc." + configurer . ClusterDomain , options [ 0 ] . DNSSearch )
}
if len ( options [ 1 ] . DNS ) != 1 || options [ 1 ] . DNS [ 0 ] != "127.0.0.1" {
t . Errorf ( "expected nameserver 127.0.0.1, got %+v" , options [ 1 ] . DNS )
}
if len ( options [ 1 ] . DNSSearch ) != 1 || options [ 1 ] . DNSSearch [ 0 ] != "." {
t . Errorf ( "expected search \".\", got %+v" , options [ 1 ] . DNSSearch )
}
if len ( options [ 2 ] . DNS ) != 1 || options [ 2 ] . DNS [ 0 ] != clusterNS {
t . Errorf ( "expected nameserver %s, got %+v" , clusterNS , options [ 2 ] . DNS )
}
if len ( options [ 2 ] . DNSSearch ) == 0 || options [ 2 ] . DNSSearch [ 0 ] != ".svc." + configurer . ClusterDomain {
t . Errorf ( "expected search %s, got %+v" , ".svc." + configurer . ClusterDomain , options [ 2 ] . DNSSearch )
}
if len ( options [ 3 ] . DNS ) != 1 || options [ 3 ] . DNS [ 0 ] != "127.0.0.1" {
t . Errorf ( "expected nameserver 127.0.0.1, got %+v" , options [ 3 ] . DNS )
}
if len ( options [ 3 ] . DNSSearch ) != 1 || options [ 3 ] . DNSSearch [ 0 ] != "." {
t . Errorf ( "expected search \".\", got %+v" , options [ 3 ] . DNSSearch )
}
testResolverConfig := "/etc/resolv.conf"
configurer = NewConfigurer ( recorder , nodeRef , nil , testClusterDNS , testClusterDNSDomain , testResolverConfig )
for i , pod := range pods {
var err error
2017-11-17 02:44:13 +00:00
dnsConfig , err := configurer . GetPodDNS ( pod )
2017-11-14 02:26:06 +00:00
if err != nil {
t . Fatalf ( "failed to generate container options: %v" , err )
}
2017-11-17 02:44:13 +00:00
options [ i ] . DNS , options [ i ] . DNSSearch = dnsConfig . Servers , dnsConfig . Searches
2017-11-14 02:26:06 +00:00
}
t . Logf ( "nameservers %+v" , options [ 1 ] . DNS )
if len ( options [ 0 ] . DNS ) != 1 {
t . Errorf ( "expected cluster nameserver only, got %+v" , options [ 0 ] . DNS )
} else if options [ 0 ] . DNS [ 0 ] != clusterNS {
t . Errorf ( "expected nameserver %s, got %v" , clusterNS , options [ 0 ] . DNS [ 0 ] )
}
expLength := len ( options [ 1 ] . DNSSearch ) + 3
if expLength > 6 {
expLength = 6
}
if len ( options [ 0 ] . DNSSearch ) != expLength {
t . Errorf ( "expected prepend of cluster domain, got %+v" , options [ 0 ] . DNSSearch )
} else if options [ 0 ] . DNSSearch [ 0 ] != ".svc." + configurer . ClusterDomain {
t . Errorf ( "expected domain %s, got %s" , ".svc." + configurer . ClusterDomain , options [ 0 ] . DNSSearch )
}
if len ( options [ 2 ] . DNS ) != 1 {
t . Errorf ( "expected cluster nameserver only, got %+v" , options [ 2 ] . DNS )
} else if options [ 2 ] . DNS [ 0 ] != clusterNS {
t . Errorf ( "expected nameserver %s, got %v" , clusterNS , options [ 2 ] . DNS [ 0 ] )
}
if len ( options [ 2 ] . DNSSearch ) != expLength {
t . Errorf ( "expected prepend of cluster domain, got %+v" , options [ 2 ] . DNSSearch )
} else if options [ 2 ] . DNSSearch [ 0 ] != ".svc." + configurer . ClusterDomain {
t . Errorf ( "expected domain %s, got %s" , ".svc." + configurer . ClusterDomain , options [ 0 ] . DNSSearch )
}
}
2017-11-19 03:46:24 +00:00
func TestGetPodDNSCustom ( t * testing . T ) {
customDNSEnabled := utilfeature . DefaultFeatureGate . Enabled ( "CustomPodDNS" )
defer func ( ) {
// Restoring the old value.
if err := utilfeature . DefaultFeatureGate . Set ( fmt . Sprintf ( "CustomPodDNS=%v" , customDNSEnabled ) ) ; err != nil {
t . Errorf ( "Failed to set CustomPodDNS feature gate: %v" , err )
}
} ( )
recorder := record . NewFakeRecorder ( 20 )
nodeRef := & v1 . ObjectReference {
Kind : "Node" ,
Name : string ( "testNode" ) ,
UID : types . UID ( "testNode" ) ,
Namespace : "" ,
}
2018-02-22 02:32:58 +00:00
testPodNamespace := "testNS"
testClusterNameserver := "10.0.0.10"
testClusterDNSDomain := "kubernetes.io"
testSvcDomain := fmt . Sprintf ( "svc.%s" , testClusterDNSDomain )
testNsSvcDomain := fmt . Sprintf ( "%s.svc.%s" , testPodNamespace , testClusterDNSDomain )
testNdotsOptionValue := "3"
testHostNameserver := "8.8.8.8"
testHostDomain := "host.domain"
2017-11-19 03:46:24 +00:00
2018-02-22 02:32:58 +00:00
testPod := & v1 . Pod {
2017-11-19 03:46:24 +00:00
ObjectMeta : metav1 . ObjectMeta {
2018-02-22 02:32:58 +00:00
Name : "test_pod" ,
Namespace : testPodNamespace ,
2017-11-19 03:46:24 +00:00
} ,
}
2018-02-22 02:32:58 +00:00
resolvConfContent := [ ] byte ( fmt . Sprintf ( "nameserver %s\nsearch %s\n" , testHostNameserver , testHostDomain ) )
tmpfile , err := ioutil . TempFile ( "" , "tmpResolvConf" )
2017-11-19 03:46:24 +00:00
if err != nil {
2018-02-22 02:32:58 +00:00
t . Fatal ( err )
}
defer os . Remove ( tmpfile . Name ( ) )
if _ , err := tmpfile . Write ( resolvConfContent ) ; err != nil {
t . Fatal ( err )
}
if err := tmpfile . Close ( ) ; err != nil {
t . Fatal ( err )
2017-11-19 03:46:24 +00:00
}
2018-02-22 02:32:58 +00:00
configurer := NewConfigurer ( recorder , nodeRef , nil , [ ] net . IP { net . ParseIP ( testClusterNameserver ) } , testClusterDNSDomain , tmpfile . Name ( ) )
2017-11-19 03:46:24 +00:00
testCases := [ ] struct {
desc string
customPodDNSFeatureGate bool
2018-02-22 02:32:58 +00:00
hostnetwork bool
dnsPolicy v1 . DNSPolicy
2017-11-19 03:46:24 +00:00
dnsConfig * v1 . PodDNSConfig
expectedDNSConfig * runtimeapi . DNSConfig
} {
{
2018-02-22 02:32:58 +00:00
desc : "feature gate is disabled, DNSNone should fallback to DNSClusterFirst" ,
dnsPolicy : v1 . DNSNone ,
expectedDNSConfig : & runtimeapi . DNSConfig {
Servers : [ ] string { testClusterNameserver } ,
Searches : [ ] string { testNsSvcDomain , testSvcDomain , testClusterDNSDomain , testHostDomain } ,
Options : [ ] string { "ndots:5" } ,
} ,
2017-11-19 03:46:24 +00:00
} ,
{
desc : "feature gate is enabled, DNSNone without DNSConfig should have empty DNS settings" ,
customPodDNSFeatureGate : true ,
2018-02-22 02:32:58 +00:00
dnsPolicy : v1 . DNSNone ,
2017-11-19 03:46:24 +00:00
expectedDNSConfig : & runtimeapi . DNSConfig { } ,
} ,
{
desc : "feature gate is enabled, DNSNone with DNSConfig should have a merged DNS settings" ,
customPodDNSFeatureGate : true ,
2018-02-22 02:32:58 +00:00
dnsPolicy : v1 . DNSNone ,
2017-11-19 03:46:24 +00:00
dnsConfig : & v1 . PodDNSConfig {
2018-02-22 02:32:58 +00:00
Nameservers : [ ] string { "203.0.113.1" } ,
2017-11-19 03:46:24 +00:00
Searches : [ ] string { "my.domain" , "second.domain" } ,
Options : [ ] v1 . PodDNSConfigOption {
2018-02-22 02:32:58 +00:00
{ Name : "ndots" , Value : & testNdotsOptionValue } ,
2017-11-19 03:46:24 +00:00
{ Name : "debug" } ,
} ,
} ,
expectedDNSConfig : & runtimeapi . DNSConfig {
2018-02-22 02:32:58 +00:00
Servers : [ ] string { "203.0.113.1" } ,
2017-11-19 03:46:24 +00:00
Searches : [ ] string { "my.domain" , "second.domain" } ,
Options : [ ] string { "ndots:3" , "debug" } ,
} ,
} ,
2018-02-22 02:32:58 +00:00
{
desc : "feature gate is enabled, DNSClusterFirst with DNSConfig should have a merged DNS settings" ,
customPodDNSFeatureGate : true ,
dnsPolicy : v1 . DNSClusterFirst ,
dnsConfig : & v1 . PodDNSConfig {
Nameservers : [ ] string { "10.0.0.11" } ,
Searches : [ ] string { "my.domain" } ,
Options : [ ] v1 . PodDNSConfigOption {
{ Name : "ndots" , Value : & testNdotsOptionValue } ,
{ Name : "debug" } ,
} ,
} ,
expectedDNSConfig : & runtimeapi . DNSConfig {
Servers : [ ] string { testClusterNameserver , "10.0.0.11" } ,
Searches : [ ] string { testNsSvcDomain , testSvcDomain , testClusterDNSDomain , testHostDomain , "my.domain" } ,
Options : [ ] string { "ndots:3" , "debug" } ,
} ,
} ,
{
desc : "feature gate is enabled, DNSClusterFirstWithHostNet with DNSConfig should have a merged DNS settings" ,
customPodDNSFeatureGate : true ,
hostnetwork : true ,
dnsPolicy : v1 . DNSClusterFirstWithHostNet ,
dnsConfig : & v1 . PodDNSConfig {
Nameservers : [ ] string { "10.0.0.11" } ,
Searches : [ ] string { "my.domain" } ,
Options : [ ] v1 . PodDNSConfigOption {
{ Name : "ndots" , Value : & testNdotsOptionValue } ,
{ Name : "debug" } ,
} ,
} ,
expectedDNSConfig : & runtimeapi . DNSConfig {
Servers : [ ] string { testClusterNameserver , "10.0.0.11" } ,
Searches : [ ] string { testNsSvcDomain , testSvcDomain , testClusterDNSDomain , testHostDomain , "my.domain" } ,
Options : [ ] string { "ndots:3" , "debug" } ,
} ,
} ,
{
desc : "feature gate is enabled, DNSDefault with DNSConfig should have a merged DNS settings" ,
customPodDNSFeatureGate : true ,
dnsPolicy : v1 . DNSDefault ,
dnsConfig : & v1 . PodDNSConfig {
Nameservers : [ ] string { "10.0.0.11" } ,
Searches : [ ] string { "my.domain" } ,
Options : [ ] v1 . PodDNSConfigOption {
{ Name : "ndots" , Value : & testNdotsOptionValue } ,
{ Name : "debug" } ,
} ,
} ,
expectedDNSConfig : & runtimeapi . DNSConfig {
Servers : [ ] string { testHostNameserver , "10.0.0.11" } ,
Searches : [ ] string { testHostDomain , "my.domain" } ,
Options : [ ] string { "ndots:3" , "debug" } ,
} ,
} ,
2017-11-19 03:46:24 +00:00
}
for _ , tc := range testCases {
if err := utilfeature . DefaultFeatureGate . Set ( fmt . Sprintf ( "CustomPodDNS=%v" , tc . customPodDNSFeatureGate ) ) ; err != nil {
t . Errorf ( "Failed to set CustomPodDNS feature gate: %v" , err )
}
2018-02-22 02:32:58 +00:00
testPod . Spec . HostNetwork = tc . hostnetwork
testPod . Spec . DNSConfig = tc . dnsConfig
testPod . Spec . DNSPolicy = tc . dnsPolicy
2017-11-19 03:46:24 +00:00
2018-02-22 02:32:58 +00:00
resDNSConfig , err := configurer . GetPodDNS ( testPod )
2017-11-19 03:46:24 +00:00
if err != nil {
2018-02-22 02:32:58 +00:00
t . Errorf ( "%s: GetPodDNS(%v), unexpected error: %v" , tc . desc , testPod , err )
2017-11-19 03:46:24 +00:00
}
if ! dnsConfigsAreEqual ( resDNSConfig , tc . expectedDNSConfig ) {
2018-02-22 02:32:58 +00:00
t . Errorf ( "%s: GetPodDNS(%v)=%v, want %v" , tc . desc , testPod , resDNSConfig , tc . expectedDNSConfig )
2017-11-19 03:46:24 +00:00
}
}
}
func dnsConfigsAreEqual ( resConfig , expectedConfig * runtimeapi . DNSConfig ) bool {
if len ( resConfig . Servers ) != len ( expectedConfig . Servers ) ||
len ( resConfig . Searches ) != len ( expectedConfig . Searches ) ||
len ( resConfig . Options ) != len ( expectedConfig . Options ) {
return false
}
for i , server := range resConfig . Servers {
if expectedConfig . Servers [ i ] != server {
return false
}
}
for i , search := range resConfig . Searches {
if expectedConfig . Searches [ i ] != search {
return false
}
}
// Options order may be changed after conversion.
return sets . NewString ( resConfig . Options ... ) . Equal ( sets . NewString ( expectedConfig . Options ... ) )
}
2017-11-14 02:26:06 +00:00
func newTestPods ( count int ) [ ] * v1 . Pod {
pods := make ( [ ] * v1 . Pod , count )
for i := 0 ; i < count ; i ++ {
pods [ i ] = & v1 . Pod {
Spec : v1 . PodSpec {
HostNetwork : true ,
} ,
ObjectMeta : metav1 . ObjectMeta {
UID : types . UID ( 10000 + i ) ,
Name : fmt . Sprintf ( "pod%d" , i ) ,
} ,
}
}
return pods
}