k8s.io/kubernetes@v1.29.3/test/e2e/network/dns_configmap.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package network
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"time"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/kubernetes/test/e2e/framework"
    27  	e2eservice "k8s.io/kubernetes/test/e2e/framework/service"
    28  	"k8s.io/kubernetes/test/e2e/network/common"
    29  
    30  	"github.com/onsi/ginkgo/v2"
    31  )
    32  
    33  var (
    34  	googleDNSHostname = "dns.google"
    35  	// The ConfigMap update mechanism takes longer than the standard
    36  	// wait.ForeverTestTimeout.
    37  	moreForeverTestTimeout = 2 * 60 * time.Second
    38  )
    39  
    40  type dnsNameserverTest struct {
    41  	dnsTestCommon
    42  }
    43  
    44  func (t *dnsNameserverTest) run(ctx context.Context, isIPv6 bool) {
    45  	t.init(ctx)
    46  
    47  	t.createUtilPodLabel(ctx, "e2e-dns-configmap")
    48  	ginkgo.DeferCleanup(t.deleteUtilPod)
    49  	originalConfigMapData := t.fetchDNSConfigMapData(ctx)
    50  	ginkgo.DeferCleanup(t.restoreDNSConfigMap, originalConfigMapData)
    51  
    52  	if isIPv6 {
    53  		t.createDNSServer(ctx, t.f.Namespace.Name, map[string]string{
    54  			"abc.acme.local": "2606:4700:4700::1111",
    55  			"def.acme.local": "2606:4700:4700::2222",
    56  			"widget.local":   "2606:4700:4700::3333",
    57  		})
    58  	} else {
    59  		t.createDNSServer(ctx, t.f.Namespace.Name, map[string]string{
    60  			"abc.acme.local": "1.1.1.1",
    61  			"def.acme.local": "2.2.2.2",
    62  			"widget.local":   "3.3.3.3",
    63  		})
    64  	}
    65  	ginkgo.DeferCleanup(t.deleteDNSServerPod)
    66  
    67  	if t.name == "coredns" {
    68  		t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{
    69  			"Corefile": fmt.Sprintf(`.:53 {
    70          health
    71          ready
    72          kubernetes %v in-addr.arpa ip6.arpa {
    73             pods insecure
    74             fallthrough in-addr.arpa ip6.arpa
    75             ttl 30
    76          }
    77          forward . %v
    78      }
    79       acme.local:53 {
    80         forward . %v
    81      }`, framework.TestContext.ClusterDNSDomain, t.dnsServerPod.Status.PodIP, t.dnsServerPod.Status.PodIP),
    82  		}})
    83  
    84  		t.deleteCoreDNSPods(ctx)
    85  	} else {
    86  		t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{
    87  			"stubDomains":         fmt.Sprintf(`{"acme.local":["%v"]}`, t.dnsServerPod.Status.PodIP),
    88  			"upstreamNameservers": fmt.Sprintf(`["%v"]`, t.dnsServerPod.Status.PodIP),
    89  		}})
    90  	}
    91  
    92  	if isIPv6 {
    93  		t.checkDNSRecordFrom(
    94  			"abc.acme.local",
    95  			func(actual []string) bool { return len(actual) == 1 && actual[0] == "2606:4700:4700::1111" },
    96  			"cluster-dns-ipv6",
    97  			moreForeverTestTimeout)
    98  		t.checkDNSRecordFrom(
    99  			"def.acme.local",
   100  			func(actual []string) bool { return len(actual) == 1 && actual[0] == "2606:4700:4700::2222" },
   101  			"cluster-dns-ipv6",
   102  			moreForeverTestTimeout)
   103  		t.checkDNSRecordFrom(
   104  			"widget.local",
   105  			func(actual []string) bool { return len(actual) == 1 && actual[0] == "2606:4700:4700::3333" },
   106  			"cluster-dns-ipv6",
   107  			moreForeverTestTimeout)
   108  	} else {
   109  		t.checkDNSRecordFrom(
   110  			"abc.acme.local",
   111  			func(actual []string) bool { return len(actual) == 1 && actual[0] == "1.1.1.1" },
   112  			"cluster-dns",
   113  			moreForeverTestTimeout)
   114  		t.checkDNSRecordFrom(
   115  			"def.acme.local",
   116  			func(actual []string) bool { return len(actual) == 1 && actual[0] == "2.2.2.2" },
   117  			"cluster-dns",
   118  			moreForeverTestTimeout)
   119  		t.checkDNSRecordFrom(
   120  			"widget.local",
   121  			func(actual []string) bool { return len(actual) == 1 && actual[0] == "3.3.3.3" },
   122  			"cluster-dns",
   123  			moreForeverTestTimeout)
   124  	}
   125  
   126  	t.restoreDNSConfigMap(ctx, originalConfigMapData)
   127  	// Wait for the deleted ConfigMap to take effect, otherwise the
   128  	// configuration can bleed into other tests.
   129  	t.checkDNSRecordFrom(
   130  		"abc.acme.local",
   131  		func(actual []string) bool { return len(actual) == 0 },
   132  		"cluster-dns",
   133  		moreForeverTestTimeout)
   134  }
   135  
   136  type dnsPtrFwdTest struct {
   137  	dnsTestCommon
   138  }
   139  
   140  func (t *dnsPtrFwdTest) run(ctx context.Context, isIPv6 bool) {
   141  	t.init(ctx)
   142  
   143  	t.createUtilPodLabel(ctx, "e2e-dns-configmap")
   144  	ginkgo.DeferCleanup(t.deleteUtilPod)
   145  	originalConfigMapData := t.fetchDNSConfigMapData(ctx)
   146  	ginkgo.DeferCleanup(t.restoreDNSConfigMap, originalConfigMapData)
   147  
   148  	t.createDNSServerWithPtrRecord(ctx, t.f.Namespace.Name, isIPv6)
   149  	ginkgo.DeferCleanup(t.deleteDNSServerPod)
   150  
   151  	// Should still be able to lookup public nameserver without explicit upstream nameserver set.
   152  	if isIPv6 {
   153  		t.checkDNSRecordFrom(
   154  			"2001:4860:4860::8888",
   155  			func(actual []string) bool { return len(actual) == 1 && actual[0] == googleDNSHostname+"." },
   156  			"ptr-record",
   157  			moreForeverTestTimeout)
   158  	} else {
   159  		t.checkDNSRecordFrom(
   160  			"8.8.8.8",
   161  			func(actual []string) bool { return len(actual) == 1 && actual[0] == googleDNSHostname+"." },
   162  			"ptr-record",
   163  			moreForeverTestTimeout)
   164  	}
   165  
   166  	if t.name == "coredns" {
   167  		t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{
   168  			"Corefile": fmt.Sprintf(`.:53 {
   169          health
   170          ready
   171          kubernetes %v in-addr.arpa ip6.arpa {
   172             pods insecure
   173             fallthrough in-addr.arpa ip6.arpa
   174             ttl 30
   175          }
   176          forward . %v
   177      }`, framework.TestContext.ClusterDNSDomain, t.dnsServerPod.Status.PodIP),
   178  		}})
   179  
   180  		t.deleteCoreDNSPods(ctx)
   181  	} else {
   182  		t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{
   183  			"upstreamNameservers": fmt.Sprintf(`["%v"]`, t.dnsServerPod.Status.PodIP),
   184  		}})
   185  	}
   186  
   187  	if isIPv6 {
   188  		t.checkDNSRecordFrom(
   189  			"2001:db8::29",
   190  			func(actual []string) bool { return len(actual) == 1 && actual[0] == "my.test." },
   191  			"ptr-record",
   192  			moreForeverTestTimeout)
   193  
   194  		t.restoreDNSConfigMap(ctx, originalConfigMapData)
   195  		t.checkDNSRecordFrom(
   196  			"2001:db8::29",
   197  			func(actual []string) bool { return len(actual) == 0 },
   198  			"ptr-record",
   199  			moreForeverTestTimeout)
   200  
   201  	} else {
   202  		t.checkDNSRecordFrom(
   203  			"192.0.2.123",
   204  			func(actual []string) bool { return len(actual) == 1 && actual[0] == "my.test." },
   205  			"ptr-record",
   206  			moreForeverTestTimeout)
   207  
   208  		t.restoreDNSConfigMap(ctx, originalConfigMapData)
   209  		t.checkDNSRecordFrom(
   210  			"192.0.2.123",
   211  			func(actual []string) bool { return len(actual) == 0 },
   212  			"ptr-record",
   213  			moreForeverTestTimeout)
   214  	}
   215  }
   216  
   217  type dnsExternalNameTest struct {
   218  	dnsTestCommon
   219  }
   220  
   221  func (t *dnsExternalNameTest) run(ctx context.Context, isIPv6 bool) {
   222  	t.init(ctx)
   223  
   224  	t.createUtilPodLabel(ctx, "e2e-dns-configmap")
   225  	ginkgo.DeferCleanup(t.deleteUtilPod)
   226  	originalConfigMapData := t.fetchDNSConfigMapData(ctx)
   227  	ginkgo.DeferCleanup(t.restoreDNSConfigMap, originalConfigMapData)
   228  
   229  	fooHostname := "foo.example.com"
   230  	if isIPv6 {
   231  		t.createDNSServer(ctx, t.f.Namespace.Name, map[string]string{
   232  			fooHostname: "2001:db8::29",
   233  		})
   234  	} else {
   235  		t.createDNSServer(ctx, t.f.Namespace.Name, map[string]string{
   236  			fooHostname: "192.0.2.123",
   237  		})
   238  	}
   239  	ginkgo.DeferCleanup(t.deleteDNSServerPod)
   240  
   241  	f := t.f
   242  	serviceName := "dns-externalname-upstream-test"
   243  	externalNameService := e2eservice.CreateServiceSpec(serviceName, googleDNSHostname, false, nil)
   244  	if _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, externalNameService, metav1.CreateOptions{}); err != nil {
   245  		ginkgo.Fail(fmt.Sprintf("ginkgo.Failed when creating service: %v", err))
   246  	}
   247  	ginkgo.DeferCleanup(f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete, externalNameService.Name, metav1.DeleteOptions{})
   248  	serviceNameLocal := "dns-externalname-upstream-local"
   249  	externalNameServiceLocal := e2eservice.CreateServiceSpec(serviceNameLocal, fooHostname, false, nil)
   250  	if _, err := f.ClientSet.CoreV1().Services(f.Namespace.Name).Create(ctx, externalNameServiceLocal, metav1.CreateOptions{}); err != nil {
   251  		ginkgo.Fail(fmt.Sprintf("ginkgo.Failed when creating service: %v", err))
   252  	}
   253  	ginkgo.DeferCleanup(f.ClientSet.CoreV1().Services(f.Namespace.Name).Delete, externalNameServiceLocal.Name, metav1.DeleteOptions{})
   254  
   255  	if isIPv6 {
   256  		t.checkDNSRecordFrom(
   257  			fmt.Sprintf("%s.%s.svc.%s", serviceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
   258  			func(actual []string) bool {
   259  				return len(actual) >= 1 && actual[0] == googleDNSHostname+"."
   260  			},
   261  			"cluster-dns-ipv6",
   262  			moreForeverTestTimeout)
   263  	} else {
   264  		t.checkDNSRecordFrom(
   265  			fmt.Sprintf("%s.%s.svc.%s", serviceName, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
   266  			func(actual []string) bool {
   267  				return len(actual) >= 1 && actual[0] == googleDNSHostname+"."
   268  			},
   269  			"cluster-dns",
   270  			moreForeverTestTimeout)
   271  	}
   272  
   273  	if t.name == "coredns" {
   274  		t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{
   275  			"Corefile": fmt.Sprintf(`.:53 {
   276          health
   277          ready
   278          kubernetes %v in-addr.arpa ip6.arpa {
   279             pods insecure
   280             fallthrough in-addr.arpa ip6.arpa
   281             ttl 30
   282          }
   283          forward . %v
   284      }`, framework.TestContext.ClusterDNSDomain, t.dnsServerPod.Status.PodIP),
   285  		}})
   286  
   287  		t.deleteCoreDNSPods(ctx)
   288  	} else {
   289  		t.setConfigMap(ctx, &v1.ConfigMap{Data: map[string]string{
   290  			"upstreamNameservers": fmt.Sprintf(`["%v"]`, t.dnsServerPod.Status.PodIP),
   291  		}})
   292  	}
   293  	if isIPv6 {
   294  		t.checkDNSRecordFrom(
   295  			fmt.Sprintf("%s.%s.svc.%s", serviceNameLocal, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
   296  			func(actual []string) bool {
   297  				return len(actual) >= 2 && actual[0] == fooHostname+"." && actual[1] == "2001:db8::29"
   298  			},
   299  			"cluster-dns-ipv6",
   300  			moreForeverTestTimeout)
   301  	} else {
   302  		t.checkDNSRecordFrom(
   303  			fmt.Sprintf("%s.%s.svc.%s", serviceNameLocal, f.Namespace.Name, framework.TestContext.ClusterDNSDomain),
   304  			func(actual []string) bool {
   305  				return len(actual) == 2 && actual[0] == fooHostname+"." && actual[1] == "192.0.2.123"
   306  			},
   307  			"cluster-dns",
   308  			moreForeverTestTimeout)
   309  	}
   310  
   311  	t.restoreDNSConfigMap(ctx, originalConfigMapData)
   312  }
   313  
   314  var _ = common.SIGDescribe("DNS configMap nameserver", func() {
   315  
   316  	ginkgo.Context("Change stubDomain", func() {
   317  		nsTest := &dnsNameserverTest{dnsTestCommon: newDNSTestCommon()}
   318  
   319  		framework.It("should be able to change stubDomain configuration", framework.WithSlow(), framework.WithSerial(), func(ctx context.Context) {
   320  			nsTest.c = nsTest.f.ClientSet
   321  			nsTest.run(ctx, framework.TestContext.ClusterIsIPv6())
   322  		})
   323  	})
   324  
   325  	ginkgo.Context("Forward PTR lookup", func() {
   326  		fwdTest := &dnsPtrFwdTest{dnsTestCommon: newDNSTestCommon()}
   327  
   328  		framework.It("should forward PTR records lookup to upstream nameserver", framework.WithSlow(), framework.WithSerial(), func(ctx context.Context) {
   329  			fwdTest.c = fwdTest.f.ClientSet
   330  			fwdTest.run(ctx, framework.TestContext.ClusterIsIPv6())
   331  		})
   332  	})
   333  
   334  	ginkgo.Context("Forward external name lookup", func() {
   335  		externalNameTest := &dnsExternalNameTest{dnsTestCommon: newDNSTestCommon()}
   336  
   337  		framework.It("should forward externalname lookup to upstream nameserver", framework.WithSlow(), framework.WithSerial(), func(ctx context.Context) {
   338  			externalNameTest.c = externalNameTest.f.ClientSet
   339  			externalNameTest.run(ctx, framework.TestContext.ClusterIsIPv6())
   340  		})
   341  	})
   342  })