From 6d8459166d0f63333b539ba4499eab37ace2004b Mon Sep 17 00:00:00 2001 From: Sandeep Rajan Date: Thu, 18 Jan 2018 15:28:02 -0500 Subject: [PATCH] kube-dns configmap translate --- cmd/kubeadm/app/phases/addons/dns/BUILD | 3 + cmd/kubeadm/app/phases/addons/dns/dns.go | 68 ++++++++- cmd/kubeadm/app/phases/addons/dns/dns_test.go | 142 +++++++++++++++++- .../app/phases/addons/dns/manifests.go | 17 ++- 4 files changed, 220 insertions(+), 10 deletions(-) diff --git a/cmd/kubeadm/app/phases/addons/dns/BUILD b/cmd/kubeadm/app/phases/addons/dns/BUILD index ef8c19b2b8d..6065970f275 100644 --- a/cmd/kubeadm/app/phases/addons/dns/BUILD +++ b/cmd/kubeadm/app/phases/addons/dns/BUILD @@ -19,7 +19,9 @@ go_test( "//cmd/kubeadm/app/util:go_default_library", "//pkg/apis/core:go_default_library", "//pkg/util/version:go_default_library", + "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/client-go/kubernetes/fake:go_default_library", "//vendor/k8s.io/client-go/testing:go_default_library", @@ -41,6 +43,7 @@ go_library( "//cmd/kubeadm/app/util:go_default_library", "//cmd/kubeadm/app/util/apiclient:go_default_library", "//pkg/api/legacyscheme:go_default_library", + "//pkg/kubelet/types:go_default_library", "//pkg/util/version:go_default_library", "//vendor/k8s.io/api/apps/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", diff --git a/cmd/kubeadm/app/phases/addons/dns/dns.go b/cmd/kubeadm/app/phases/addons/dns/dns.go index 4f1db3d045e..84a8219e44a 100644 --- a/cmd/kubeadm/app/phases/addons/dns/dns.go +++ b/cmd/kubeadm/app/phases/addons/dns/dns.go @@ -18,7 +18,11 @@ package dns import ( "fmt" + "runtime" + "strings" + + "encoding/json" apps "k8s.io/api/apps/v1" "k8s.io/api/core/v1" @@ -33,12 +37,15 @@ import ( kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" "k8s.io/kubernetes/pkg/api/legacyscheme" + kubetypes "k8s.io/kubernetes/pkg/kubelet/types" "k8s.io/kubernetes/pkg/util/version" ) const ( // KubeDNSServiceAccountName describes the name of the ServiceAccount for the kube-dns addon - KubeDNSServiceAccountName = "kube-dns" + KubeDNSServiceAccountName = "kube-dns" + kubeDNSStubDomain = "stubDomains" + kubeDNSUpstreamNameservers = "upstreamNameservers" ) // EnsureDNSAddon creates the kube-dns or CoreDNS addon @@ -139,11 +146,27 @@ func coreDNSAddon(cfg *kubeadmapi.MasterConfiguration, client clientset.Interfac if err != nil { return fmt.Errorf("error when parsing CoreDNS deployment template: %v", err) } + kubeDNSConfigMap, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(kubeadmconstants.KubeDNS, metav1.GetOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + return err + } + + stubDomain, err := translateStubDomainOfKubeDNSToProxyCoreDNS(kubeDNSStubDomain, kubeDNSConfigMap) + if err != nil { + return err + } + + upstreamNameserver, err := translateUpstreamNameServerOfKubeDNSToUpstreamProxyCoreDNS(kubeDNSUpstreamNameservers, kubeDNSConfigMap) + if err != nil { + return err + } // Get the config file for CoreDNS - coreDNSConfigMapBytes, err := kubeadmutil.ParseTemplate(CoreDNSConfigMap, struct{ DNSDomain, ServiceCIDR string }{ - ServiceCIDR: cfg.Networking.ServiceSubnet, - DNSDomain: cfg.Networking.DNSDomain, + coreDNSConfigMapBytes, err := kubeadmutil.ParseTemplate(CoreDNSConfigMap, struct{ DNSDomain, ServiceCIDR, UpstreamNameserver, StubDomain string }{ + ServiceCIDR: cfg.Networking.ServiceSubnet, + DNSDomain: cfg.Networking.DNSDomain, + UpstreamNameserver: upstreamNameserver, + StubDomain: stubDomain, }) if err != nil { return fmt.Errorf("error when parsing CoreDNS configMap template: %v", err) @@ -244,3 +267,40 @@ func createDNSService(dnsService *v1.Service, serviceBytes []byte, client client } return nil } + +// translateStubDomainOfKubeDNSToProxyCoreDNS translates StubDomain Data in kube-dns ConfigMap +// in the form of Proxy for the CoreDNS Corefile. +func translateStubDomainOfKubeDNSToProxyCoreDNS(dataField string, kubeDNSConfigMap *v1.ConfigMap) (string, error) { + if proxy, ok := kubeDNSConfigMap.Data[dataField]; ok { + stubDomainData := make(map[string][]string) + proxyStanzaList := coreDNSProxyStanzaPrefix + + err := json.Unmarshal([]byte(proxy), &stubDomainData) + if err != nil { + return "", fmt.Errorf("failed to parse JSON from 'kube-dns ConfigMap: %v", err) + } + + for domain, proxyIP := range stubDomainData { + proxyStanzaList = proxyStanzaList + domain + coreDNSProxyDefaultPort + coreDNSCorefileDefaultData + strings.Join(proxyIP, " ") + coreDNSProxyStanzaSuffix + } + return proxyStanzaList, nil + } + return "", nil +} + +// translateUpstreamNameServerOfKubeDNSToUpstreamProxyCoreDNS translates UpstreamNameServer Data in kube-dns ConfigMap +// in the form of Proxy for the CoreDNS Corefile. +func translateUpstreamNameServerOfKubeDNSToUpstreamProxyCoreDNS(dataField string, kubeDNSConfigMap *v1.ConfigMap) (string, error) { + if upstreamValues, ok := kubeDNSConfigMap.Data[dataField]; ok { + var upstreamProxyIP []string + + err := json.Unmarshal([]byte(upstreamValues), &upstreamProxyIP) + if err != nil { + return "", fmt.Errorf("failed to parse JSON from 'kube-dns ConfigMap: %v", err) + } + + coreDNSProxyStanzaList := strings.Join(upstreamProxyIP, " ") + return coreDNSProxyStanzaList, nil + } + return kubetypes.ResolvConfDefault, nil +} diff --git a/cmd/kubeadm/app/phases/addons/dns/dns_test.go b/cmd/kubeadm/app/phases/addons/dns/dns_test.go index c144dc49e04..91a19a36bd7 100644 --- a/cmd/kubeadm/app/phases/addons/dns/dns_test.go +++ b/cmd/kubeadm/app/phases/addons/dns/dns_test.go @@ -17,9 +17,12 @@ limitations under the License. package dns import ( + "strings" "testing" + "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" clientsetfake "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" @@ -127,9 +130,11 @@ func TestCompileManifests(t *testing.T) { }, { manifest: CoreDNSConfigMap, - data: struct{ DNSDomain, ServiceCIDR string }{ - DNSDomain: "foo", - ServiceCIDR: "foo", + data: struct{ DNSDomain, ServiceCIDR, UpstreamNameserver, StubDomain string }{ + DNSDomain: "foo", + ServiceCIDR: "foo", + UpstreamNameserver: "foo", + StubDomain: "foo", }, expected: true, }, @@ -175,3 +180,134 @@ func TestGetDNSIP(t *testing.T) { } } } + +func TestTranslateStubDomainKubeDNSToCoreDNS(t *testing.T) { + testCases := []struct { + configMap *v1.ConfigMap + expect string + }{ + { + configMap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-dns", + Namespace: "kube-system", + }, + Data: map[string]string{ + "stubDomains": `{"foo.com" : ["1.2.3.4:5300","3.3.3.3"], "my.cluster.local" : ["2.3.4.5"]}`, + "upstreamNameservers": `["8.8.8.8", "8.8.4.4"]`, + }, + }, + + expect: ` + foo.com:53 { + errors + cache 30 + proxy . 1.2.3.4:5300 3.3.3.3 + } + my.cluster.local:53 { + errors + cache 30 + proxy . 2.3.4.5 + } + `, + }, + { + configMap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kubedns", + Namespace: "kube-system", + }, + }, + + expect: "", + }, + { + configMap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-dns", + Namespace: "kube-system", + }, + Data: map[string]string{ + "stubDomains": `{"foo.com" : ["1.2.3.4:5300"], "my.cluster.local" : ["2.3.4.5"]}`, + "upstreamNameservers": `["8.8.8.8", "8.8.4.4"]`, + }, + }, + + expect: ` + foo.com:53 { + errors + cache 30 + proxy . 1.2.3.4:5300 + } + my.cluster.local:53 { + errors + cache 30 + proxy . 2.3.4.5 + } + `, + }, + } + for _, testCase := range testCases { + out, err := translateStubDomainOfKubeDNSToProxyCoreDNS(kubeDNSStubDomain, testCase.configMap) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if !strings.Contains(out, testCase.expect) { + t.Errorf("expected to find %q in output: %q", testCase.expect, out) + } + } +} + +func TestTranslateUpstreamKubeDNSToCoreDNS(t *testing.T) { + testCases := []struct { + configMap *v1.ConfigMap + expect string + }{ + { + configMap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-dns", + Namespace: "kube-system", + }, + }, + + expect: "/etc/resolv.conf", + }, + { + configMap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kubedns", + Namespace: "kube-system", + }, + Data: map[string]string{ + "stubDomains": ` {"foo.com" : ["1.2.3.4:5300"], "my.cluster.local" : ["2.3.4.5"]}`, + "upstreamNameservers": `["8.8.8.8", "8.8.4.4", "4.4.4.4"]`, + }, + }, + + expect: "8.8.8.8 8.8.4.4 4.4.4.4", + }, + { + configMap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kubedns", + Namespace: "kube-system", + }, + Data: map[string]string{ + "upstreamNameservers": `["8.8.8.8", "8.8.4.4"]`, + }, + }, + + expect: "8.8.8.8 8.8.4.4", + }, + } + for _, testCase := range testCases { + out, err := translateUpstreamNameServerOfKubeDNSToUpstreamProxyCoreDNS(kubeDNSUpstreamNameservers, testCase.configMap) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if !strings.Contains(out, testCase.expect) { + t.Errorf("expected to find %q in output: %q", testCase.expect, out) + } + } +} diff --git a/cmd/kubeadm/app/phases/addons/dns/manifests.go b/cmd/kubeadm/app/phases/addons/dns/manifests.go index b3d1ee8f07d..69a493d05de 100644 --- a/cmd/kubeadm/app/phases/addons/dns/manifests.go +++ b/cmd/kubeadm/app/phases/addons/dns/manifests.go @@ -309,13 +309,13 @@ data: health kubernetes {{ .DNSDomain }} {{ .ServiceCIDR }} { pods insecure - upstream /etc/resolv.conf + upstream {{ .UpstreamNameserver }} fallthrough in-addr.arpa ip6.arpa } prometheus :9153 - proxy . /etc/resolv.conf + proxy . {{ .UpstreamNameserver }} cache 30 - } + }{{ .StubDomain }} ` // CoreDNSClusterRole is the CoreDNS ClusterRole manifest CoreDNSClusterRole = ` @@ -358,4 +358,15 @@ metadata: name: coredns namespace: kube-system ` + // coreDNSProxyDefaultPort, coreDNSCorefileDefaultData, coreDNSProxyStanzaSuffix is used in the translation of configMap of kube-dns to CoreDNS. + coreDNSProxyStanzaPrefix = ` + ` + coreDNSProxyDefaultPort = `:53` + coreDNSCorefileDefaultData = ` { + errors + cache 30 + proxy . ` + coreDNSProxyStanzaSuffix = ` + } + ` )