From 6317ce63c6ae33b15e90ac7eb6fbbd9d6cae72c3 Mon Sep 17 00:00:00 2001 From: Gunju Kim Date: Mon, 24 May 2021 20:10:02 +0900 Subject: [PATCH] Add feature gate ExpandedDNSConfig ExpandedDNSConfig allows kubernetes to have expanded DNS(Domain Name System) configuration --- pkg/api/pod/util.go | 2 + pkg/apis/core/validation/validation.go | 30 ++-- pkg/apis/core/validation/validation_test.go | 118 ++++++++++++++- pkg/features/kube_features.go | 7 + pkg/kubelet/network/dns/dns.go | 33 ++++- pkg/kubelet/network/dns/dns_test.go | 151 ++++++++++++++++---- 6 files changed, 296 insertions(+), 45 deletions(-) diff --git a/pkg/api/pod/util.go b/pkg/api/pod/util.go index 4a26cccb5bf..6bd6149f68d 100644 --- a/pkg/api/pod/util.go +++ b/pkg/api/pod/util.go @@ -402,6 +402,8 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po // Do not allow pod spec to use non-integer multiple of huge page unit size default AllowIndivisibleHugePagesValues: false, AllowWindowsHostProcessField: utilfeature.DefaultFeatureGate.Enabled(features.WindowsHostProcessContainers), + // Allow pod spec with expanded DNS configuration + AllowExpandedDNSConfig: utilfeature.DefaultFeatureGate.Enabled(features.ExpandedDNSConfig), } if oldPodSpec != nil { diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index 0848bed6576..10ab0ae00b4 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -2961,10 +2961,14 @@ const ( // restrictions in Linux libc name resolution handling. // Max number of DNS name servers. MaxDNSNameservers = 3 - // Max number of domains in search path. - MaxDNSSearchPaths = 6 - // Max number of characters in search path. - MaxDNSSearchListChars = 256 + // Expanded max number of domains in the search path list. + MaxDNSSearchPathsExpanded = 32 + // Expanded max number of characters in the search path. + MaxDNSSearchListCharsExpanded = 2048 + // Max number of domains in the search path list. + MaxDNSSearchPathsLegacy = 6 + // Max number of characters in the search path list. + MaxDNSSearchListCharsLegacy = 256 ) func validateReadinessGates(readinessGates []core.PodReadinessGate, fldPath *field.Path) field.ErrorList { @@ -2977,7 +2981,7 @@ func validateReadinessGates(readinessGates []core.PodReadinessGate, fldPath *fie return allErrs } -func validatePodDNSConfig(dnsConfig *core.PodDNSConfig, dnsPolicy *core.DNSPolicy, fldPath *field.Path) field.ErrorList { +func validatePodDNSConfig(dnsConfig *core.PodDNSConfig, dnsPolicy *core.DNSPolicy, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { allErrs := field.ErrorList{} // Validate DNSNone case. Must provide at least one DNS name server. @@ -3001,12 +3005,16 @@ func validatePodDNSConfig(dnsConfig *core.PodDNSConfig, dnsPolicy *core.DNSPolic } } // Validate searches. - if len(dnsConfig.Searches) > MaxDNSSearchPaths { - allErrs = append(allErrs, field.Invalid(fldPath.Child("searches"), dnsConfig.Searches, fmt.Sprintf("must not have more than %v search paths", MaxDNSSearchPaths))) + maxDNSSearchPaths, maxDNSSearchListChars := MaxDNSSearchPathsLegacy, MaxDNSSearchListCharsLegacy + if opts.AllowExpandedDNSConfig { + maxDNSSearchPaths, maxDNSSearchListChars = MaxDNSSearchPathsExpanded, MaxDNSSearchListCharsExpanded + } + if len(dnsConfig.Searches) > maxDNSSearchPaths { + allErrs = append(allErrs, field.Invalid(fldPath.Child("searches"), dnsConfig.Searches, fmt.Sprintf("must not have more than %v search paths", maxDNSSearchPaths))) } // Include the space between search paths. - if len(strings.Join(dnsConfig.Searches, " ")) > MaxDNSSearchListChars { - allErrs = append(allErrs, field.Invalid(fldPath.Child("searches"), dnsConfig.Searches, "must not have more than 256 characters (including spaces) in the search list")) + if len(strings.Join(dnsConfig.Searches, " ")) > maxDNSSearchListChars { + allErrs = append(allErrs, field.Invalid(fldPath.Child("searches"), dnsConfig.Searches, fmt.Sprintf("must not have more than %v characters (including spaces) in the search list", maxDNSSearchListChars))) } for i, search := range dnsConfig.Searches { // it is fine to have a trailing dot @@ -3206,6 +3214,8 @@ type PodValidationOptions struct { AllowIndivisibleHugePagesValues bool // Allow hostProcess field to be set in windows security context AllowWindowsHostProcessField bool + // Allow more DNSSearchPaths and longer DNSSearchListChars + AllowExpandedDNSConfig bool } // ValidatePodSingleHugePageResources checks if there are multiple huge @@ -3326,7 +3336,7 @@ func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *fi allErrs = append(allErrs, ValidatePodSecurityContext(spec.SecurityContext, spec, fldPath, fldPath.Child("securityContext"))...) allErrs = append(allErrs, validateImagePullSecrets(spec.ImagePullSecrets, fldPath.Child("imagePullSecrets"))...) allErrs = append(allErrs, validateAffinity(spec.Affinity, fldPath.Child("affinity"))...) - allErrs = append(allErrs, validatePodDNSConfig(spec.DNSConfig, &spec.DNSPolicy, fldPath.Child("dnsConfig"))...) + allErrs = append(allErrs, validatePodDNSConfig(spec.DNSConfig, &spec.DNSPolicy, fldPath.Child("dnsConfig"), opts)...) allErrs = append(allErrs, validateReadinessGates(spec.ReadinessGates, fldPath.Child("readinessGates"))...) allErrs = append(allErrs, validateTopologySpreadConstraints(spec.TopologySpreadConstraints, fldPath.Child("topologySpreadConstraints"))...) allErrs = append(allErrs, validateWindowsHostProcessPod(spec, fldPath, opts)...) diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index 4598ea2f427..72e16c5c0f6 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -6562,6 +6562,7 @@ func TestValidatePodDNSConfig(t *testing.T) { desc string dnsConfig *core.PodDNSConfig dnsPolicy *core.DNSPolicy + opts PodValidationOptions expectedError bool }{ { @@ -6608,7 +6609,7 @@ func TestValidatePodDNSConfig(t *testing.T) { expectedError: false, }, { - desc: "valid: 3 nameservers and 6 search paths", + desc: "valid: 3 nameservers and 6 search paths(legacy)", dnsConfig: &core.PodDNSConfig{ Nameservers: []string{"127.0.0.1", "10.0.0.10", "8.8.8.8"}, Searches: []string{"custom", "mydomain.com", "local", "cluster.local", "svc.cluster.local", "default.svc.cluster.local."}, @@ -6616,7 +6617,18 @@ func TestValidatePodDNSConfig(t *testing.T) { expectedError: false, }, { - desc: "valid: 256 characters in search path list", + desc: "valid: 3 nameservers and 32 search paths", + dnsConfig: &core.PodDNSConfig{ + Nameservers: []string{"127.0.0.1", "10.0.0.10", "8.8.8.8"}, + Searches: []string{"custom", "mydomain.com", "local", "cluster.local", "svc.cluster.local", "default.svc.cluster.local.", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, + }, + opts: PodValidationOptions{ + AllowExpandedDNSConfig: true, + }, + expectedError: false, + }, + { + desc: "valid: 256 characters in search path list(legacy)", dnsConfig: &core.PodDNSConfig{ // We can have 256 - (6 - 1) = 251 characters in total for 6 search paths. Searches: []string{ @@ -6630,6 +6642,50 @@ func TestValidatePodDNSConfig(t *testing.T) { }, expectedError: false, }, + { + desc: "valid: 2048 characters in search path list", + dnsConfig: &core.PodDNSConfig{ + // We can have 2048 - (32 - 1) = 2017 characters in total for 32 search paths. + Searches: []string{ + generateTestSearchPathFunc(64), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + }, + }, + opts: PodValidationOptions{ + AllowExpandedDNSConfig: true, + }, + expectedError: false, + }, { desc: "valid: ipv6 nameserver", dnsConfig: &core.PodDNSConfig{ @@ -6645,12 +6701,22 @@ func TestValidatePodDNSConfig(t *testing.T) { expectedError: true, }, { - desc: "invalid: 7 search paths", + desc: "invalid: 7 search paths(legacy)", dnsConfig: &core.PodDNSConfig{ Searches: []string{"custom", "mydomain.com", "local", "cluster.local", "svc.cluster.local", "default.svc.cluster.local", "exceeded"}, }, expectedError: true, }, + { + desc: "invalid: 33 search paths", + dnsConfig: &core.PodDNSConfig{ + Searches: []string{"custom", "mydomain.com", "local", "cluster.local", "svc.cluster.local", "default.svc.cluster.local.", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33"}, + }, + opts: PodValidationOptions{ + AllowExpandedDNSConfig: true, + }, + expectedError: true, + }, { desc: "invalid: 257 characters in search path list", dnsConfig: &core.PodDNSConfig{ @@ -6666,6 +6732,50 @@ func TestValidatePodDNSConfig(t *testing.T) { }, expectedError: true, }, + { + desc: "invalid: 2049 characters in search path list", + dnsConfig: &core.PodDNSConfig{ + // We can have 2048 - (32 - 1) = 2017 characters in total for 32 search paths. + Searches: []string{ + generateTestSearchPathFunc(65), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + generateTestSearchPathFunc(63), + }, + }, + opts: PodValidationOptions{ + AllowExpandedDNSConfig: true, + }, + expectedError: true, + }, { desc: "invalid search path", dnsConfig: &core.PodDNSConfig{ @@ -6704,7 +6814,7 @@ func TestValidatePodDNSConfig(t *testing.T) { tc.dnsPolicy = &testDNSClusterFirst } - errs := validatePodDNSConfig(tc.dnsConfig, tc.dnsPolicy, field.NewPath("dnsConfig")) + errs := validatePodDNSConfig(tc.dnsConfig, tc.dnsPolicy, field.NewPath("dnsConfig"), tc.opts) if len(errs) != 0 && !tc.expectedError { t.Errorf("%v: validatePodDNSConfig(%v) = %v, want nil", tc.desc, tc.dnsConfig, errs) } else if len(errs) == 0 && tc.expectedError { diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index f54b78c65f3..2427b194fc6 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -740,6 +740,12 @@ const ( // // StatefulSetMinReadySeconds allows minReadySeconds to be respected by StatefulSet controller StatefulSetMinReadySeconds featuregate.Feature = "StatefulSetMinReadySeconds" + + // owner: @gjkim42 + // alpha: v1.22 + // + // Enables apiserver and kubelet to allow up to 32 DNSSearchPaths and up to 2048 DNSSearchListChars. + ExpandedDNSConfig featuregate.Feature = "ExpandedDNSConfig" ) func init() { @@ -852,6 +858,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS WindowsHostProcessContainers: {Default: false, PreRelease: featuregate.Alpha}, DisableCloudProviders: {Default: false, PreRelease: featuregate.Alpha}, StatefulSetMinReadySeconds: {Default: false, PreRelease: featuregate.Alpha}, + ExpandedDNSConfig: {Default: false, PreRelease: featuregate.Alpha}, // inherited features from generic apiserver, relisted here to get a conflict if it is changed // unintentionally on either side: diff --git a/pkg/kubelet/network/dns/dns.go b/pkg/kubelet/network/dns/dns.go index 7faa017844e..02a2289efcd 100644 --- a/pkg/kubelet/network/dns/dns.go +++ b/pkg/kubelet/network/dns/dns.go @@ -28,9 +28,11 @@ import ( "k8s.io/api/core/v1" utilerrors "k8s.io/apimachinery/pkg/util/errors" utilvalidation "k8s.io/apimachinery/pkg/util/validation" + utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/tools/record" runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" "k8s.io/kubernetes/pkg/apis/core/validation" + "k8s.io/kubernetes/pkg/features" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" "k8s.io/kubernetes/pkg/kubelet/util/format" @@ -100,8 +102,13 @@ func omitDuplicates(strs []string) []string { func (c *Configurer) formDNSSearchFitsLimits(composedSearch []string, pod *v1.Pod) []string { limitsExceeded := false - if len(composedSearch) > validation.MaxDNSSearchPaths { - composedSearch = composedSearch[:validation.MaxDNSSearchPaths] + maxDNSSearchPaths, maxDNSSearchListChars := validation.MaxDNSSearchPathsLegacy, validation.MaxDNSSearchListCharsLegacy + if utilfeature.DefaultFeatureGate.Enabled(features.ExpandedDNSConfig) { + maxDNSSearchPaths, maxDNSSearchListChars = validation.MaxDNSSearchPathsExpanded, validation.MaxDNSSearchListCharsExpanded + } + + if len(composedSearch) > maxDNSSearchPaths { + composedSearch = composedSearch[:maxDNSSearchPaths] limitsExceeded = true } @@ -118,14 +125,14 @@ func (c *Configurer) formDNSSearchFitsLimits(composedSearch []string, pod *v1.Po } composedSearch = composedSearch[:l] - if resolvSearchLineStrLen := len(strings.Join(composedSearch, " ")); resolvSearchLineStrLen > validation.MaxDNSSearchListChars { + if resolvSearchLineStrLen := len(strings.Join(composedSearch, " ")); resolvSearchLineStrLen > maxDNSSearchListChars { cutDomainsNum := 0 cutDomainsLen := 0 for i := len(composedSearch) - 1; i >= 0; i-- { cutDomainsLen += len(composedSearch[i]) + 1 cutDomainsNum++ - if (resolvSearchLineStrLen - cutDomainsLen) <= validation.MaxDNSSearchListChars { + if (resolvSearchLineStrLen - cutDomainsLen) <= maxDNSSearchListChars { break } } @@ -187,7 +194,10 @@ func (c *Configurer) CheckLimitsForResolvConf() { return } - domainCountLimit := validation.MaxDNSSearchPaths + domainCountLimit, maxDNSSearchListChars := validation.MaxDNSSearchPathsLegacy, validation.MaxDNSSearchListCharsLegacy + if utilfeature.DefaultFeatureGate.Enabled(features.ExpandedDNSConfig) { + domainCountLimit, maxDNSSearchListChars = validation.MaxDNSSearchPathsExpanded, validation.MaxDNSSearchListCharsExpanded + } if c.ClusterDomain != "" { domainCountLimit -= 3 @@ -200,8 +210,17 @@ func (c *Configurer) CheckLimitsForResolvConf() { 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) + for _, search := range hostSearch { + if len(search) > utilvalidation.DNS1123SubdomainMaxLength { + log := fmt.Sprintf("Resolv.conf file %q contains a search path which length is more than allowed %d chars!", c.ResolverConfig, utilvalidation.DNS1123SubdomainMaxLength) + c.recorder.Event(c.nodeRef, v1.EventTypeWarning, "CheckLimitsForResolvConf", log) + klog.V(4).InfoS("Check limits for resolv.conf failed", "eventlog", log) + return + } + } + + if len(strings.Join(hostSearch, " ")) > maxDNSSearchListChars { + log := fmt.Sprintf("Resolv.conf file '%s' contains search line which length is more than allowed %d chars!", c.ResolverConfig, maxDNSSearchListChars) c.recorder.Event(c.nodeRef, v1.EventTypeWarning, "CheckLimitsForResolvConf", log) klog.V(4).InfoS("Check limits for resolv.conf failed", "eventlog", log) return diff --git a/pkg/kubelet/network/dns/dns_test.go b/pkg/kubelet/network/dns/dns_test.go index 9a001968627..fb84ca11678 100644 --- a/pkg/kubelet/network/dns/dns_test.go +++ b/pkg/kubelet/network/dns/dns_test.go @@ -29,8 +29,12 @@ import ( 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" + featuregatetesting "k8s.io/component-base/featuregate/testing" runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + "k8s.io/kubernetes/pkg/apis/core/validation" + "k8s.io/kubernetes/pkg/features" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -100,6 +104,26 @@ func TestParseResolvConf(t *testing.T) { } func TestFormDNSSearchFitsLimits(t *testing.T) { + searchPathList2048Chars := []string{ + // 2048 = 128 + 127 * 15 + 15 + strings.Repeat("A", 128), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + strings.Repeat("A", 127), + } + recorder := record.NewFakeRecorder(20) nodeRef := &v1.ObjectReference{ Kind: "Node", @@ -121,43 +145,93 @@ func TestFormDNSSearchFitsLimits(t *testing.T) { } testCases := []struct { - hostNames []string - resultSearch []string - events []string + desc string + hostNames []string + resultSearch []string + events []string + expandedDNSConfig bool }{ { - []string{"testNS.svc.TEST", "svc.TEST", "TEST"}, - []string{"testNS.svc.TEST", "svc.TEST", "TEST"}, - []string{}, + desc: "valid: 3 search paths", + hostNames: []string{"testNS.svc.TEST", "svc.TEST", "TEST"}, + resultSearch: []string{"testNS.svc.TEST", "svc.TEST", "TEST"}, + events: []string{}, }, { - []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB"}, - []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB"}, - []string{}, + desc: "valid: 5 search paths", + hostNames: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB"}, + resultSearch: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB"}, + events: []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"}, + desc: "invalid: longer than 256 characters in search path list", + hostNames: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", strings.Repeat("B", 256), "BBB"}, + resultSearch: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB"}, + events: []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"}, }, { - []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"}, + desc: "valid ExpandedDNSConfig: 2048 characters in search path list", + hostNames: searchPathList2048Chars, + resultSearch: searchPathList2048Chars, + events: []string{}, + expandedDNSConfig: true, + }, + + { + desc: "invalid ExpandedDNSConfig: 2050 characters in search path list", + hostNames: append(searchPathList2048Chars, "B"), + resultSearch: searchPathList2048Chars, + events: []string{fmt.Sprintf("Search Line limits were exceeded, some search paths have been omitted, the applied search line is: %s", strings.Join(searchPathList2048Chars, " "))}, + expandedDNSConfig: true, + }, + + { + desc: "invalid ExpandedDNSConfig: 256 characters search path", + hostNames: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", strings.Repeat("B", 256), "BBB"}, + resultSearch: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB"}, + events: []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"}, + expandedDNSConfig: true, + }, + + { + desc: "invalid: 7 search paths", + hostNames: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB", "CCC", "DDD"}, + resultSearch: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "AAA", "BBB", "CCC"}, + events: []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"}, + }, + + { + desc: "valid ExpandedDNSConfig: 32 search paths", + hostNames: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, + resultSearch: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, + events: []string{}, + expandedDNSConfig: true, + }, + + { + desc: "invalid ExpandedDNSConfig: 33 search paths", + hostNames: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33"}, + resultSearch: []string{"testNS.svc.TEST", "svc.TEST", "TEST", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, + events: []string{"Search Line limits were exceeded, some search paths have been omitted, the applied search line is: testNS.svc.TEST svc.TEST TEST 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32"}, + expandedDNSConfig: true, }, } 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) - } + t.Run(tc.desc, func(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandedDNSConfig, tc.expandedDNSConfig)() + + 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) + } + }) } } @@ -371,6 +445,29 @@ func TestGetPodDNSType(t *testing.T) { } func TestGetPodDNS(t *testing.T) { + testCases := []struct { + desc string + expandedDNSConfig bool + }{ + { + desc: "Not ExpandedDNSConfig", + expandedDNSConfig: false, + }, + { + desc: "ExpandedDNSConfig", + expandedDNSConfig: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ExpandedDNSConfig, tc.expandedDNSConfig)() + testGetPodDNS(t) + }) + } +} + +func testGetPodDNS(t *testing.T) { recorder := record.NewFakeRecorder(20) nodeRef := &v1.ObjectReference{ Kind: "Node", @@ -445,8 +542,14 @@ func TestGetPodDNS(t *testing.T) { t.Errorf("expected nameserver %s, got %v", clusterNS, options[0].DNS[0]) } expLength := len(options[1].DNSSearch) + 3 - if expLength > 6 { - expLength = 6 + + maxDNSSearchPaths := validation.MaxDNSSearchPathsLegacy + if utilfeature.DefaultFeatureGate.Enabled(features.ExpandedDNSConfig) { + maxDNSSearchPaths = validation.MaxDNSSearchPathsExpanded + } + + if expLength > maxDNSSearchPaths { + expLength = maxDNSSearchPaths } if len(options[0].DNSSearch) != expLength { t.Errorf("expected prepend of cluster domain, got %+v", options[0].DNSSearch)