Add generated file

This PR adds generated files under pkg/client and vendor folder.
This commit is contained in:
xing-yang
2018-07-12 10:55:15 -07:00
parent 36b1de0341
commit e213d1890d
17729 changed files with 5090889 additions and 0 deletions

17
vendor/k8s.io/kubernetes/pkg/kubelet/network/BUILD generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/kubelet/network/dns:all-srcs",
],
tags = ["automanaged"],
)

8
vendor/k8s.io/kubernetes/pkg/kubelet/network/OWNERS generated vendored Normal file
View File

@@ -0,0 +1,8 @@
approvers:
- thockin
- dchen1107
- matchstick
- freehan
reviewers:
- sig-network-reviewers

50
vendor/k8s.io/kubernetes/pkg/kubelet/network/dns/BUILD generated vendored Normal file
View File

@@ -0,0 +1,50 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["dns.go"],
importpath = "k8s.io/kubernetes/pkg/kubelet/network/dns",
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/core/validation:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubelet/apis/cri/runtime/v1alpha2:go_default_library",
"//pkg/kubelet/container:go_default_library",
"//pkg/kubelet/util/format:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//vendor/k8s.io/client-go/tools/record:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["dns_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/kubelet/apis/cri/runtime/v1alpha2:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/stretchr/testify/require:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//vendor/k8s.io/client-go/tools/record:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,4 @@
approvers:
- sig-network-approvers
reviewers:
- sig-network-reviewers

414
vendor/k8s.io/kubernetes/pkg/kubelet/network/dns/dns.go generated vendored Normal file
View File

@@ -0,0 +1,414 @@
/*
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"
"io"
"io/ioutil"
"net"
"os"
"path/filepath"
"strings"
"k8s.io/api/core/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/tools/record"
"k8s.io/kubernetes/pkg/apis/core/validation"
"k8s.io/kubernetes/pkg/features"
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
"k8s.io/kubernetes/pkg/kubelet/util/format"
"github.com/golang/glog"
)
var (
// The default dns opt strings.
defaultDNSOptions = []string{"ndots:5"}
)
type podDNSType int
const (
podDNSCluster podDNSType = iota
podDNSHost
podDNSNone
)
// Configurer is used for setting up DNS resolver configuration when launching pods.
type Configurer struct {
recorder record.EventRecorder
nodeRef *v1.ObjectReference
nodeIP net.IP
// If non-nil, use this for container DNS server.
clusterDNS []net.IP
// If non-empty, use this for container DNS search.
ClusterDomain string
// The path to the DNS resolver configuration file used as the base to generate
// the container's DNS resolver configuration file. This can be used in
// conjunction with clusterDomain and clusterDNS.
ResolverConfig string
}
// NewConfigurer returns a DNS configurer for launching pods.
func NewConfigurer(recorder record.EventRecorder, nodeRef *v1.ObjectReference, nodeIP net.IP, clusterDNS []net.IP, clusterDomain, resolverConfig string) *Configurer {
return &Configurer{
recorder: recorder,
nodeRef: nodeRef,
nodeIP: nodeIP,
clusterDNS: clusterDNS,
ClusterDomain: clusterDomain,
ResolverConfig: resolverConfig,
}
}
func omitDuplicates(strs []string) []string {
uniqueStrs := make(map[string]bool)
var ret []string
for _, str := range strs {
if !uniqueStrs[str] {
ret = append(ret, str)
uniqueStrs[str] = true
}
}
return ret
}
func (c *Configurer) formDNSSearchFitsLimits(composedSearch []string, pod *v1.Pod) []string {
limitsExceeded := false
if len(composedSearch) > validation.MaxDNSSearchPaths {
composedSearch = composedSearch[:validation.MaxDNSSearchPaths]
limitsExceeded = true
}
if resolvSearchLineStrLen := len(strings.Join(composedSearch, " ")); resolvSearchLineStrLen > validation.MaxDNSSearchListChars {
cutDomainsNum := 0
cutDomainsLen := 0
for i := len(composedSearch) - 1; i >= 0; i-- {
cutDomainsLen += len(composedSearch[i]) + 1
cutDomainsNum++
if (resolvSearchLineStrLen - cutDomainsLen) <= validation.MaxDNSSearchListChars {
break
}
}
composedSearch = composedSearch[:(len(composedSearch) - cutDomainsNum)]
limitsExceeded = true
}
if limitsExceeded {
log := fmt.Sprintf("Search Line limits were exceeded, some search paths have been omitted, the applied search line is: %s", strings.Join(composedSearch, " "))
c.recorder.Event(pod, v1.EventTypeWarning, "DNSConfigForming", log)
glog.Error(log)
}
return composedSearch
}
func (c *Configurer) formDNSNameserversFitsLimits(nameservers []string, pod *v1.Pod) []string {
if len(nameservers) > validation.MaxDNSNameservers {
nameservers = nameservers[0:validation.MaxDNSNameservers]
log := fmt.Sprintf("Nameserver limits were exceeded, some nameservers have been omitted, the applied nameserver line is: %s", strings.Join(nameservers, " "))
c.recorder.Event(pod, v1.EventTypeWarning, "DNSConfigForming", log)
glog.Error(log)
}
return nameservers
}
func (c *Configurer) formDNSConfigFitsLimits(dnsConfig *runtimeapi.DNSConfig, pod *v1.Pod) *runtimeapi.DNSConfig {
dnsConfig.Servers = c.formDNSNameserversFitsLimits(dnsConfig.Servers, pod)
dnsConfig.Searches = c.formDNSSearchFitsLimits(dnsConfig.Searches, pod)
return dnsConfig
}
func (c *Configurer) generateSearchesForDNSClusterFirst(hostSearch []string, pod *v1.Pod) []string {
if c.ClusterDomain == "" {
return hostSearch
}
nsSvcDomain := fmt.Sprintf("%s.svc.%s", pod.Namespace, c.ClusterDomain)
svcDomain := fmt.Sprintf("svc.%s", c.ClusterDomain)
clusterSearch := []string{nsSvcDomain, svcDomain, c.ClusterDomain}
return omitDuplicates(append(clusterSearch, hostSearch...))
}
// CheckLimitsForResolvConf checks limits in resolv.conf.
func (c *Configurer) CheckLimitsForResolvConf() {
f, err := os.Open(c.ResolverConfig)
if err != nil {
c.recorder.Event(c.nodeRef, v1.EventTypeWarning, "CheckLimitsForResolvConf", err.Error())
glog.Error("CheckLimitsForResolvConf: " + err.Error())
return
}
defer f.Close()
_, hostSearch, _, err := parseResolvConf(f)
if err != nil {
c.recorder.Event(c.nodeRef, v1.EventTypeWarning, "CheckLimitsForResolvConf", err.Error())
glog.Error("CheckLimitsForResolvConf: " + err.Error())
return
}
domainCountLimit := validation.MaxDNSSearchPaths
if c.ClusterDomain != "" {
domainCountLimit -= 3
}
if len(hostSearch) > domainCountLimit {
log := fmt.Sprintf("Resolv.conf file '%s' contains search line consisting of more than %d domains!", c.ResolverConfig, domainCountLimit)
c.recorder.Event(c.nodeRef, v1.EventTypeWarning, "CheckLimitsForResolvConf", log)
glog.Error("CheckLimitsForResolvConf: " + log)
return
}
if len(strings.Join(hostSearch, " ")) > validation.MaxDNSSearchListChars {
log := fmt.Sprintf("Resolv.conf file '%s' contains search line which length is more than allowed %d chars!", c.ResolverConfig, validation.MaxDNSSearchListChars)
c.recorder.Event(c.nodeRef, v1.EventTypeWarning, "CheckLimitsForResolvConf", log)
glog.Error("CheckLimitsForResolvConf: " + log)
return
}
return
}
// parseResolveConf reads a resolv.conf file from the given reader, and parses
// it into nameservers, searches and options, possibly returning an error.
func parseResolvConf(reader io.Reader) (nameservers []string, searches []string, options []string, err error) {
file, err := ioutil.ReadAll(reader)
if err != nil {
return nil, nil, nil, err
}
// Lines of the form "nameserver 1.2.3.4" accumulate.
nameservers = []string{}
// Lines of the form "search example.com" overrule - last one wins.
searches = []string{}
// Lines of the form "option ndots:5 attempts:2" overrule - last one wins.
// Each option is recorded as an element in the array.
options = []string{}
lines := strings.Split(string(file), "\n")
for l := range lines {
trimmed := strings.TrimSpace(lines[l])
if strings.HasPrefix(trimmed, "#") {
continue
}
fields := strings.Fields(trimmed)
if len(fields) == 0 {
continue
}
if fields[0] == "nameserver" && len(fields) >= 2 {
nameservers = append(nameservers, fields[1])
}
if fields[0] == "search" {
searches = fields[1:]
}
if fields[0] == "options" {
options = fields[1:]
}
}
return nameservers, searches, options, nil
}
func (c *Configurer) getHostDNSConfig(pod *v1.Pod) (*runtimeapi.DNSConfig, error) {
var hostDNS, hostSearch, hostOptions []string
// Get host DNS settings
if c.ResolverConfig != "" {
f, err := os.Open(c.ResolverConfig)
if err != nil {
return nil, err
}
defer f.Close()
hostDNS, hostSearch, hostOptions, err = parseResolvConf(f)
if err != nil {
return nil, err
}
}
return &runtimeapi.DNSConfig{
Servers: hostDNS,
Searches: hostSearch,
Options: hostOptions,
}, nil
}
func getPodDNSType(pod *v1.Pod) (podDNSType, error) {
dnsPolicy := pod.Spec.DNSPolicy
switch dnsPolicy {
case v1.DNSNone:
if utilfeature.DefaultFeatureGate.Enabled(features.CustomPodDNS) {
return podDNSNone, nil
}
// This should not happen as kube-apiserver should have rejected
// setting dnsPolicy to DNSNone when feature gate is disabled.
return podDNSCluster, fmt.Errorf(fmt.Sprintf("invalid DNSPolicy=%v: custom pod DNS is disabled", dnsPolicy))
case v1.DNSClusterFirstWithHostNet:
return podDNSCluster, nil
case v1.DNSClusterFirst:
if !kubecontainer.IsHostNetworkPod(pod) {
return podDNSCluster, nil
}
// Fallback to DNSDefault for pod on hostnetowrk.
fallthrough
case v1.DNSDefault:
return podDNSHost, nil
}
// This should not happen as kube-apiserver should have rejected
// invalid dnsPolicy.
return podDNSCluster, fmt.Errorf(fmt.Sprintf("invalid DNSPolicy=%v", dnsPolicy))
}
// Merge DNS options. If duplicated, entries given by PodDNSConfigOption will
// overwrite the existing ones.
func mergeDNSOptions(existingDNSConfigOptions []string, dnsConfigOptions []v1.PodDNSConfigOption) []string {
optionsMap := make(map[string]string)
for _, op := range existingDNSConfigOptions {
if index := strings.Index(op, ":"); index != -1 {
optionsMap[op[:index]] = op[index+1:]
} else {
optionsMap[op] = ""
}
}
for _, op := range dnsConfigOptions {
if op.Value != nil {
optionsMap[op.Name] = *op.Value
} else {
optionsMap[op.Name] = ""
}
}
// Reconvert DNS options into a string array.
options := []string{}
for opName, opValue := range optionsMap {
op := opName
if opValue != "" {
op = op + ":" + opValue
}
options = append(options, op)
}
return options
}
// appendDNSConfig appends DNS servers, search paths and options given by
// PodDNSConfig to the existing DNS config. Duplicated entries will be merged.
// This assumes existingDNSConfig and dnsConfig are not nil.
func appendDNSConfig(existingDNSConfig *runtimeapi.DNSConfig, dnsConfig *v1.PodDNSConfig) *runtimeapi.DNSConfig {
existingDNSConfig.Servers = omitDuplicates(append(existingDNSConfig.Servers, dnsConfig.Nameservers...))
existingDNSConfig.Searches = omitDuplicates(append(existingDNSConfig.Searches, dnsConfig.Searches...))
existingDNSConfig.Options = mergeDNSOptions(existingDNSConfig.Options, dnsConfig.Options)
return existingDNSConfig
}
// GetPodDNS returns DNS settings for the pod.
func (c *Configurer) GetPodDNS(pod *v1.Pod) (*runtimeapi.DNSConfig, error) {
dnsConfig, err := c.getHostDNSConfig(pod)
if err != nil {
return nil, err
}
dnsType, err := getPodDNSType(pod)
if err != nil {
glog.Errorf("Failed to get DNS type for pod %q: %v. Falling back to DNSClusterFirst policy.", format.Pod(pod), err)
dnsType = podDNSCluster
}
switch dnsType {
case podDNSNone:
// DNSNone should use empty DNS settings as the base.
dnsConfig = &runtimeapi.DNSConfig{}
case podDNSCluster:
if len(c.clusterDNS) != 0 {
// For a pod with DNSClusterFirst policy, the cluster DNS server is
// the only nameserver configured for the pod. The cluster DNS server
// itself will forward queries to other nameservers that is configured
// to use, in case the cluster DNS server cannot resolve the DNS query
// itself.
dnsConfig.Servers = []string{}
for _, ip := range c.clusterDNS {
dnsConfig.Servers = append(dnsConfig.Servers, ip.String())
}
dnsConfig.Searches = c.generateSearchesForDNSClusterFirst(dnsConfig.Searches, pod)
dnsConfig.Options = defaultDNSOptions
break
}
// clusterDNS is not known. Pod with ClusterDNSFirst Policy cannot be created.
nodeErrorMsg := fmt.Sprintf("kubelet does not have ClusterDNS IP configured and cannot create Pod using %q policy. Falling back to %q policy.", v1.DNSClusterFirst, v1.DNSDefault)
c.recorder.Eventf(c.nodeRef, v1.EventTypeWarning, "MissingClusterDNS", nodeErrorMsg)
c.recorder.Eventf(pod, v1.EventTypeWarning, "MissingClusterDNS", "pod: %q. %s", format.Pod(pod), nodeErrorMsg)
// Fallback to DNSDefault.
fallthrough
case podDNSHost:
// When the kubelet --resolv-conf flag is set to the empty string, use
// DNS settings that override the docker default (which is to use
// /etc/resolv.conf) and effectively disable DNS lookups. According to
// the bind documentation, the behavior of the DNS client library when
// "nameservers" are not specified is to "use the nameserver on the
// local machine". A nameserver setting of localhost is equivalent to
// this documented behavior.
if c.ResolverConfig == "" {
switch {
case c.nodeIP == nil || c.nodeIP.To4() != nil:
dnsConfig.Servers = []string{"127.0.0.1"}
case c.nodeIP.To16() != nil:
dnsConfig.Servers = []string{"::1"}
}
dnsConfig.Searches = []string{"."}
}
}
if utilfeature.DefaultFeatureGate.Enabled(features.CustomPodDNS) && pod.Spec.DNSConfig != nil {
dnsConfig = appendDNSConfig(dnsConfig, pod.Spec.DNSConfig)
}
return c.formDNSConfigFitsLimits(dnsConfig, pod), nil
}
// SetupDNSinContainerizedMounter replaces the nameserver in containerized-mounter's rootfs/etc/resolve.conf with kubelet.ClusterDNS
func (c *Configurer) SetupDNSinContainerizedMounter(mounterPath string) {
resolvePath := filepath.Join(strings.TrimSuffix(mounterPath, "/mounter"), "rootfs", "etc", "resolv.conf")
dnsString := ""
for _, dns := range c.clusterDNS {
dnsString = dnsString + fmt.Sprintf("nameserver %s\n", dns)
}
if c.ResolverConfig != "" {
f, err := os.Open(c.ResolverConfig)
defer f.Close()
if err != nil {
glog.Error("Could not open resolverConf file")
} else {
_, hostSearch, _, err := parseResolvConf(f)
if err != nil {
glog.Errorf("Error for parsing the reslov.conf file: %v", err)
} else {
dnsString = dnsString + "search"
for _, search := range hostSearch {
dnsString = dnsString + fmt.Sprintf(" %s", search)
}
dnsString = dnsString + "\n"
}
}
}
if err := ioutil.WriteFile(resolvePath, []byte(dnsString), 0600); err != nil {
glog.Errorf("Could not write dns nameserver in file %s, with error %v", resolvePath, err)
}
}

View File

@@ -0,0 +1,675 @@
/*
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"
"io/ioutil"
"net"
"os"
"strings"
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/tools/record"
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var (
fetchEvent = func(recorder *record.FakeRecorder) string {
select {
case event := <-recorder.Events:
return event
default:
return ""
}
}
)
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)
}
}
func TestFormDNSSearchFitsLimits(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 {
hostNames []string
resultSearch []string
events []string
}{
{
[]string{"testNS.svc.TEST", "svc.TEST", "TEST"},
[]string{"testNS.svc.TEST", "svc.TEST", "TEST"},
[]string{},
},
{
[]string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB"},
[]string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB"},
[]string{},
},
{
[]string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", strings.Repeat("B", 256), "BBB"},
[]string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA"},
[]string{"Search Line limits were exceeded, some search paths have been omitted, the applied search line is: testNS.svc.TEST svc.TEST TEST AAA"},
},
{
[]string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB", "CCC", "DDD"},
[]string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB", "CCC"},
[]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"},
},
}
for i, tc := range testCases {
dnsSearch := configurer.formDNSSearchFitsLimits(tc.hostNames, pod)
assert.EqualValues(t, tc.resultSearch, dnsSearch, "test [%d]", i)
for _, expectedEvent := range tc.events {
expected := fmt.Sprintf("%s %s %s", v1.EventTypeWarning, "DNSConfigForming", expectedEvent)
event := fetchEvent(recorder)
assert.Equal(t, expected, event, "test [%d]", i)
}
}
}
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)
}
}
}
func TestGetPodDNS(t *testing.T) {
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
dnsConfig, err := configurer.GetPodDNS(pod)
if err != nil {
t.Fatalf("failed to generate container options: %v", err)
}
options[i].DNS, options[i].DNSSearch = dnsConfig.Servers, dnsConfig.Searches
}
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
dnsConfig, err := configurer.GetPodDNS(pod)
if err != nil {
t.Fatalf("failed to generate container options: %v", err)
}
options[i].DNS, options[i].DNSSearch = dnsConfig.Servers, dnsConfig.Searches
}
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)
}
}
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: "",
}
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"
testPod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test_pod",
Namespace: testPodNamespace,
},
}
resolvConfContent := []byte(fmt.Sprintf("nameserver %s\nsearch %s\n", testHostNameserver, testHostDomain))
tmpfile, err := ioutil.TempFile("", "tmpResolvConf")
if err != nil {
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)
}
configurer := NewConfigurer(recorder, nodeRef, nil, []net.IP{net.ParseIP(testClusterNameserver)}, testClusterDNSDomain, tmpfile.Name())
testCases := []struct {
desc string
customPodDNSFeatureGate bool
hostnetwork bool
dnsPolicy v1.DNSPolicy
dnsConfig *v1.PodDNSConfig
expectedDNSConfig *runtimeapi.DNSConfig
}{
{
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"},
},
},
{
desc: "feature gate is enabled, DNSNone without DNSConfig should have empty DNS settings",
customPodDNSFeatureGate: true,
dnsPolicy: v1.DNSNone,
expectedDNSConfig: &runtimeapi.DNSConfig{},
},
{
desc: "feature gate is enabled, DNSNone with DNSConfig should have a merged DNS settings",
customPodDNSFeatureGate: true,
dnsPolicy: v1.DNSNone,
dnsConfig: &v1.PodDNSConfig{
Nameservers: []string{"203.0.113.1"},
Searches: []string{"my.domain", "second.domain"},
Options: []v1.PodDNSConfigOption{
{Name: "ndots", Value: &testNdotsOptionValue},
{Name: "debug"},
},
},
expectedDNSConfig: &runtimeapi.DNSConfig{
Servers: []string{"203.0.113.1"},
Searches: []string{"my.domain", "second.domain"},
Options: []string{"ndots:3", "debug"},
},
},
{
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"},
},
},
}
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)
}
testPod.Spec.HostNetwork = tc.hostnetwork
testPod.Spec.DNSConfig = tc.dnsConfig
testPod.Spec.DNSPolicy = tc.dnsPolicy
resDNSConfig, err := configurer.GetPodDNS(testPod)
if err != nil {
t.Errorf("%s: GetPodDNS(%v), unexpected error: %v", tc.desc, testPod, err)
}
if !dnsConfigsAreEqual(resDNSConfig, tc.expectedDNSConfig) {
t.Errorf("%s: GetPodDNS(%v)=%v, want %v", tc.desc, testPod, resDNSConfig, tc.expectedDNSConfig)
}
}
}
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...))
}
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
}