kube-proxy: internal config: refactor ClusterCIDR

Refactor ClusterCIDR for internal configuration of kube-proxy
adhering to the v1alpha2 version specifications as detailed in
https://kep.k8s.io/784.

Signed-off-by: Daman Arora <aroradaman@gmail.com>
This commit is contained in:
Daman Arora
2024-07-17 23:46:28 +05:30
parent 380adb93cc
commit c57e1156f5
12 changed files with 348 additions and 129 deletions

View File

@@ -141,6 +141,10 @@ type DetectLocalConfiguration struct {
// LocalModeBridgeInterface, kube-proxy will consider traffic to be local if
// it originates from this bridge.
BridgeInterface string
// clusterCIDRs is the dual-stack list of CIDR ranges of the pods in the cluster. When
// DetectLocalMode is set to LocalModeClusterCIDR, kube-proxy will consider
// traffic to be local if its source IP is in the range of any given CIDR.
ClusterCIDRs []string
// interfaceNamePrefix is an interface name prefix. When DetectLocalMode is set to
// LocalModeInterfaceNamePrefix, kube-proxy will consider traffic to be local if
// it originates from any interface whose name begins with this prefix.
@@ -212,12 +216,6 @@ type KubeProxyConfiguration struct {
DetectLocalMode LocalMode
// detectLocal contains optional configuration settings related to DetectLocalMode.
DetectLocal DetectLocalConfiguration
// clusterCIDR is the CIDR range of the pods in the cluster. (For dual-stack
// clusters, this can be a comma-separated dual-stack pair of CIDR ranges.). When
// DetectLocalMode is set to LocalModeClusterCIDR, kube-proxy will consider
// traffic to be local if its source IP is in this range. (Otherwise it is not
// used.)
ClusterCIDR string
// nodePortAddresses is a list of CIDR ranges that contain valid node IPs, or
// alternatively, the single string 'primary'. If set to a list of CIDRs,

View File

@@ -17,6 +17,8 @@ limitations under the License.
package v1alpha1
import (
"strings"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/kube-proxy/config/v1alpha1"
"k8s.io/kubernetes/pkg/proxy/apis/config"
@@ -48,6 +50,10 @@ func Convert_config_KubeProxyConfiguration_To_v1alpha1_KubeProxyConfiguration(in
out.IPTables.SyncPeriod = in.SyncPeriod
out.IPTables.MinSyncPeriod = in.MinSyncPeriod
}
if len(in.DetectLocal.ClusterCIDRs) > 0 {
out.ClusterCIDR = strings.Join(in.DetectLocal.ClusterCIDRs, ",")
}
return nil
}
@@ -77,6 +83,10 @@ func Convert_v1alpha1_KubeProxyConfiguration_To_config_KubeProxyConfiguration(in
out.SyncPeriod = in.IPTables.SyncPeriod
out.MinSyncPeriod = in.IPTables.MinSyncPeriod
}
if len(in.ClusterCIDR) > 0 {
out.DetectLocal.ClusterCIDRs = strings.Split(in.ClusterCIDR, ",")
}
return nil
}
@@ -94,3 +104,8 @@ func Convert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfigur
func Convert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration(in *v1alpha1.KubeProxyNFTablesConfiguration, out *config.KubeProxyNFTablesConfiguration, scope conversion.Scope) error {
return autoConvert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration(in, out, scope)
}
// Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration is defined here, because public conversion is not auto-generated due to existing warnings.
func Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(in *config.DetectLocalConfiguration, out *v1alpha1.DetectLocalConfiguration, s conversion.Scope) error {
return autoConvert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(in, out, s)
}

View File

@@ -44,11 +44,6 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.DetectLocalConfiguration)(nil), (*v1alpha1.DetectLocalConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(a.(*config.DetectLocalConfiguration), b.(*v1alpha1.DetectLocalConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1alpha1.KubeProxyConntrackConfiguration)(nil), (*config.KubeProxyConntrackConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_KubeProxyConntrackConfiguration_To_config_KubeProxyConntrackConfiguration(a.(*v1alpha1.KubeProxyConntrackConfiguration), b.(*config.KubeProxyConntrackConfiguration), scope)
}); err != nil {
@@ -84,6 +79,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*config.DetectLocalConfiguration)(nil), (*v1alpha1.DetectLocalConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(a.(*config.DetectLocalConfiguration), b.(*v1alpha1.DetectLocalConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*config.KubeProxyConfiguration)(nil), (*v1alpha1.KubeProxyConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_KubeProxyConfiguration_To_v1alpha1_KubeProxyConfiguration(a.(*config.KubeProxyConfiguration), b.(*v1alpha1.KubeProxyConfiguration), scope)
}); err != nil {
@@ -125,15 +125,11 @@ func Convert_v1alpha1_DetectLocalConfiguration_To_config_DetectLocalConfiguratio
func autoConvert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(in *config.DetectLocalConfiguration, out *v1alpha1.DetectLocalConfiguration, s conversion.Scope) error {
out.BridgeInterface = in.BridgeInterface
// WARNING: in.ClusterCIDRs requires manual conversion: does not exist in peer-type
out.InterfaceNamePrefix = in.InterfaceNamePrefix
return nil
}
// Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration is an autogenerated conversion function.
func Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(in *config.DetectLocalConfiguration, out *v1alpha1.DetectLocalConfiguration, s conversion.Scope) error {
return autoConvert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(in, out, s)
}
func autoConvert_v1alpha1_KubeProxyConfiguration_To_config_KubeProxyConfiguration(in *v1alpha1.KubeProxyConfiguration, out *config.KubeProxyConfiguration, s conversion.Scope) error {
out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates))
if err := componentbaseconfigv1alpha1.Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil {
@@ -164,7 +160,7 @@ func autoConvert_v1alpha1_KubeProxyConfiguration_To_config_KubeProxyConfiguratio
if err := Convert_v1alpha1_DetectLocalConfiguration_To_config_DetectLocalConfiguration(&in.DetectLocal, &out.DetectLocal, s); err != nil {
return err
}
out.ClusterCIDR = in.ClusterCIDR
// WARNING: in.ClusterCIDR requires manual conversion: does not exist in peer-type
out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses))
// WARNING: in.OOMScoreAdj requires manual conversion: does not exist in peer-type
// WARNING: in.Conntrack requires manual conversion: does not exist in peer-type
@@ -206,7 +202,6 @@ func autoConvert_config_KubeProxyConfiguration_To_v1alpha1_KubeProxyConfiguratio
if err := Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(&in.DetectLocal, &out.DetectLocal, s); err != nil {
return err
}
out.ClusterCIDR = in.ClusterCIDR
out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses))
// WARNING: in.SyncPeriod requires manual conversion: does not exist in peer-type
// WARNING: in.MinSyncPeriod requires manual conversion: does not exist in peer-type

View File

@@ -80,25 +80,6 @@ func Validate(config *kubeproxyconfig.KubeProxyConfiguration) field.ErrorList {
}
allErrs = append(allErrs, validateHostPort(config.MetricsBindAddress, newPath.Child("MetricsBindAddress"))...)
if config.ClusterCIDR != "" {
cidrs := strings.Split(config.ClusterCIDR, ",")
switch {
case len(cidrs) > 2:
allErrs = append(allErrs, field.Invalid(newPath.Child("ClusterCIDR"), config.ClusterCIDR, "only one CIDR allowed or a valid DualStack CIDR (e.g. 10.100.0.0/16,fde4:8dba:82e1::/48)"))
// if DualStack and two cidrs validate if there is at least one of each IP family
case len(cidrs) == 2:
isDual, err := netutils.IsDualStackCIDRStrings(cidrs)
if err != nil || !isDual {
allErrs = append(allErrs, field.Invalid(newPath.Child("ClusterCIDR"), config.ClusterCIDR, "must be a valid DualStack CIDR (e.g. 10.100.0.0/16,fde4:8dba:82e1::/48)"))
}
// if we are here means that len(cidrs) == 1, we need to validate it
default:
if _, _, err := netutils.ParseCIDRSloppy(config.ClusterCIDR); err != nil {
allErrs = append(allErrs, field.Invalid(newPath.Child("ClusterCIDR"), config.ClusterCIDR, "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)"))
}
}
}
if _, err := utilnet.ParsePortRange(config.PortRange); err != nil {
allErrs = append(allErrs, field.Invalid(newPath.Child("PortRange"), config.PortRange, "must be a valid port range (e.g. 300-2000)"))
}
@@ -107,12 +88,7 @@ func Validate(config *kubeproxyconfig.KubeProxyConfiguration) field.ErrorList {
allErrs = append(allErrs, validateShowHiddenMetricsVersion(config.ShowHiddenMetricsForVersion, newPath.Child("ShowHiddenMetricsForVersion"))...)
allErrs = append(allErrs, validateDetectLocalMode(config.DetectLocalMode, newPath.Child("DetectLocalMode"))...)
if config.DetectLocalMode == kubeproxyconfig.LocalModeBridgeInterface {
allErrs = append(allErrs, validateInterface(config.DetectLocal.BridgeInterface, newPath.Child("InterfaceName"))...)
}
if config.DetectLocalMode == kubeproxyconfig.LocalModeInterfaceNamePrefix {
allErrs = append(allErrs, validateInterface(config.DetectLocal.InterfaceNamePrefix, newPath.Child("InterfacePrefix"))...)
}
allErrs = append(allErrs, validateDetectLocalConfiguration(config.DetectLocalMode, config.DetectLocal, newPath.Child("DetectLocalConfiguration"))...)
allErrs = append(allErrs, logsapi.Validate(&config.Logging, effectiveFeatures, newPath.Child("logging"))...)
return allErrs
@@ -338,3 +314,41 @@ func validateInterface(iface string, fldPath *field.Path) field.ErrorList {
}
return allErrs
}
func validateDualStackCIDRStrings(cidrStrings []string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
switch {
case len(cidrStrings) == 0:
allErrs = append(allErrs, field.Invalid(fldPath, cidrStrings, "must contain at least one CIDR"))
case len(cidrStrings) > 2:
allErrs = append(allErrs, field.Invalid(fldPath, cidrStrings, "must be a either a single CIDR or dual-stack pair of CIDRs (e.g. [10.100.0.0/16, fde4:8dba:82e1::/48]"))
default:
for i, cidrString := range cidrStrings {
if _, _, err := netutils.ParseCIDRSloppy(cidrString); err != nil {
allErrs = append(allErrs, field.Invalid(fldPath.Index(i), cidrString, "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)"))
}
}
if len(cidrStrings) == 2 {
ifDualStack, err := netutils.IsDualStackCIDRStrings(cidrStrings)
if err == nil && !ifDualStack {
allErrs = append(allErrs, field.Invalid(fldPath, cidrStrings, "must be a either a single CIDR or dual-stack pair of CIDRs (e.g. [10.100.0.0/16, fde4:8dba:82e1::/48]"))
}
}
}
return allErrs
}
func validateDetectLocalConfiguration(mode kubeproxyconfig.LocalMode, config kubeproxyconfig.DetectLocalConfiguration, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
switch mode {
case kubeproxyconfig.LocalModeBridgeInterface:
allErrs = append(allErrs, validateInterface(config.BridgeInterface, fldPath.Child("InterfaceName"))...)
case kubeproxyconfig.LocalModeInterfaceNamePrefix:
allErrs = append(allErrs, validateInterface(config.InterfaceNamePrefix, fldPath.Child("InterfacePrefix"))...)
case kubeproxyconfig.LocalModeClusterCIDR:
if len(config.ClusterCIDRs) > 0 {
allErrs = append(allErrs, validateDualStackCIDRStrings(config.ClusterCIDRs, fldPath.Child("ClusterCIDRs"))...)
}
}
return allErrs
}

View File

@@ -36,11 +36,14 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
BindAddress: "192.168.59.103",
HealthzBindAddress: "0.0.0.0:10256",
MetricsBindAddress: "127.0.0.1:10249",
ClusterCIDR: "192.168.59.0/24",
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{},
DetectLocalMode: kubeproxyconfig.LocalModeClusterCIDR,
DetectLocal: kubeproxyconfig.DetectLocalConfiguration{
ClusterCIDRs: []string{"192.168.59.0/24"},
},
SyncPeriod: metav1.Duration{Duration: 5 * time.Second},
MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second},
ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second},
IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{},
Linux: kubeproxyconfig.KubeProxyLinuxConfiguration{
Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
MaxPerCore: ptr.To[int32](1),
@@ -82,7 +85,7 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
config.BindAddress = "fd00:192:168:59::103"
config.HealthzBindAddress = ""
config.MetricsBindAddress = "[::1]:10249"
config.ClusterCIDR = "fd00:192:168:59::/64"
config.DetectLocal.ClusterCIDRs = []string{"fd00:192:168:59::/64"}
},
},
"alternate healthz port": {
@@ -92,12 +95,12 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
},
"ClusterCIDR is wrong IP family": {
mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
config.ClusterCIDR = "fd00:192:168::/64"
config.DetectLocal.ClusterCIDRs = []string{"fd00:192:168:59::/64"}
},
},
"ClusterCIDR is dual-stack": {
mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
config.ClusterCIDR = "192.168.59.0/24,fd00:192:168::/64"
config.DetectLocal.ClusterCIDRs = []string{"192.168.59.0/24", "fd00:192:168::/64"}
},
},
"LocalModeInterfaceNamePrefix": {
@@ -134,18 +137,6 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("MetricsBindAddress"), "127.0.0.1", "must be IP:port")},
},
"ClusterCIDR missing subset range": {
mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
config.ClusterCIDR = "192.168.59.0"
},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterCIDR"), "192.168.59.0", "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")},
},
"Invalid number of ClusterCIDRs": {
mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
config.ClusterCIDR = "192.168.59.0/24,fd00:192:168::/64,10.0.0.0/16"
},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterCIDR"), "192.168.59.0/24,fd00:192:168::/64,10.0.0.0/16", "only one CIDR allowed or a valid DualStack CIDR (e.g. 10.100.0.0/16,fde4:8dba:82e1::/48)")},
},
"ConfigSyncPeriod must be > 0": {
mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
config.ConfigSyncPeriod = metav1.Duration{Duration: -1 * time.Second}
@@ -172,24 +163,6 @@ func TestValidateKubeProxyConfiguration(t *testing.T) {
},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("SyncPeriod"), metav1.Duration{Duration: 5 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.MinSyncPeriod")},
},
"interfacePrefix is empty": {
mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
config.DetectLocalMode = kubeproxyconfig.LocalModeInterfaceNamePrefix
config.DetectLocal = kubeproxyconfig.DetectLocalConfiguration{
InterfaceNamePrefix: "",
}
},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("InterfacePrefix"), "", "must not be empty")},
},
"bridgeInterfaceName is empty": {
mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
config.DetectLocalMode = kubeproxyconfig.LocalModeBridgeInterface
config.DetectLocal = kubeproxyconfig.DetectLocalConfiguration{
InterfaceNamePrefix: "eth0", // we won't care about prefix since mode is not prefix
}
},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("InterfaceName"), "", "must not be empty")},
},
"invalid DetectLocalMode": {
mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) {
config.DetectLocalMode = "Guess"
@@ -764,3 +737,154 @@ func TestValidateKubeProxyExcludeCIDRs(t *testing.T) {
})
}
}
func TestValidateDetectLocalConfiguration(t *testing.T) {
newPath := field.NewPath("KubeProxyConfiguration")
testCases := []struct {
name string
mode kubeproxyconfig.LocalMode
config kubeproxyconfig.DetectLocalConfiguration
expectedErrs field.ErrorList
}{
{
name: "valid interface name prefix",
mode: kubeproxyconfig.LocalModeInterfaceNamePrefix,
config: kubeproxyconfig.DetectLocalConfiguration{
InterfaceNamePrefix: "vethabcde",
},
expectedErrs: field.ErrorList{},
},
{
name: "valid bridge interface",
mode: kubeproxyconfig.LocalModeBridgeInterface,
config: kubeproxyconfig.DetectLocalConfiguration{
BridgeInterface: "avz",
},
expectedErrs: field.ErrorList{},
},
{
name: "interfacePrefix is empty",
mode: kubeproxyconfig.LocalModeInterfaceNamePrefix,
config: kubeproxyconfig.DetectLocalConfiguration{
InterfaceNamePrefix: "",
},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DetectLocal").Child("InterfacePrefix"), "", "must not be empty")},
},
{
name: "bridgeInterfaceName is empty",
mode: kubeproxyconfig.LocalModeBridgeInterface,
config: kubeproxyconfig.DetectLocalConfiguration{
InterfaceNamePrefix: "eth0", // we won't care about prefix since mode is not prefix
},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DetectLocal").Child("InterfaceName"), "", "must not be empty")},
},
{
name: "valid cluster cidr",
mode: kubeproxyconfig.LocalModeClusterCIDR,
config: kubeproxyconfig.DetectLocalConfiguration{
ClusterCIDRs: []string{"192.168.59.0/24", "fd00:192:168::/64"},
},
expectedErrs: field.ErrorList{},
},
{
name: "invalid number of cluster cidrs",
mode: kubeproxyconfig.LocalModeClusterCIDR,
config: kubeproxyconfig.DetectLocalConfiguration{
ClusterCIDRs: []string{"192.168.59.0/24", "fd00:192:168::/64", "10.0.0.0/16"},
},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DetectLocal").Child("ClusterCIDRs"), []string{"192.168.59.0/24", "fd00:192:168::/64", "10.0.0.0/16"}, "must be a either a single CIDR or dual-stack pair of CIDRs (e.g. [10.100.0.0/16, fde4:8dba:82e1::/48]")},
},
{
name: "invalid cluster cidr",
mode: kubeproxyconfig.LocalModeClusterCIDR,
config: kubeproxyconfig.DetectLocalConfiguration{
ClusterCIDRs: []string{"192.168.59.0"},
},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DetectLocal").Child("ClusterCIDRs").Index(0), "192.168.59.0", "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")},
},
{
name: "empty cluster cidrs with cluster cidr mode",
mode: kubeproxyconfig.LocalModeClusterCIDR,
config: kubeproxyconfig.DetectLocalConfiguration{
ClusterCIDRs: []string{},
},
expectedErrs: field.ErrorList{},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
errs := validateDetectLocalConfiguration(tc.mode, tc.config, newPath.Child("DetectLocal"))
assert.Equalf(t, len(tc.expectedErrs), len(errs),
"expected %d errors, got %d errors: %v", len(tc.expectedErrs), len(errs), errs,
)
for i, err := range errs {
assert.Equal(t, tc.expectedErrs[i].Error(), err.Error())
}
})
}
}
func TestValidateDualStackCIDRStrings(t *testing.T) {
newPath := field.NewPath("KubeProxyConfiguration")
testCases := []struct {
name string
cidrStrings []string
expectedErrs field.ErrorList
}{
{
name: "empty cidr string",
cidrStrings: []string{},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DualStackCIDRList"), []string{}, "must contain at least one CIDR")},
},
{
name: "single ipv4 cidr",
cidrStrings: []string{"192.168.0.0/16"},
expectedErrs: field.ErrorList{},
},
{
name: "single ipv6 cidr",
cidrStrings: []string{"fd00:10:96::/112"},
expectedErrs: field.ErrorList{},
},
{
name: "dual stack cidr pair",
cidrStrings: []string{"172.16.200.0/24", "fde4:8dba:82e1::/48"},
expectedErrs: field.ErrorList{},
},
{
name: "multiple ipv4 cidrs",
cidrStrings: []string{"10.100.0.0/16", "192.168.0.0/16", "fde4:8dba:82e1::/48"},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DualStackCIDRList"), []string{"10.100.0.0/16", "192.168.0.0/16", "fde4:8dba:82e1::/48"}, "must be a either a single CIDR or dual-stack pair of CIDRs (e.g. [10.100.0.0/16, fde4:8dba:82e1::/48]")},
},
{
name: "multiple ipv6 cidrs",
cidrStrings: []string{"fd00:10:96::/112", "fde4:8dba:82e1::/48"},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DualStackCIDRList"), []string{"fd00:10:96::/112", "fde4:8dba:82e1::/48"}, "must be a either a single CIDR or dual-stack pair of CIDRs (e.g. [10.100.0.0/16, fde4:8dba:82e1::/48]")},
},
{
name: "malformed ipv4 cidr",
cidrStrings: []string{"fde4:8dba:82e1::/48", "172.16.200.0:24"},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DualStackCIDRList").Index(1), "172.16.200.0:24", "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")},
},
{
name: "malformed ipv6 cidr",
cidrStrings: []string{"fd00:10:96::", "192.168.0.0/16"},
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DualStackCIDRList").Index(0), "fd00:10:96::", "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
errs := validateDualStackCIDRStrings(tc.cidrStrings, newPath.Child("DualStackCIDRList"))
assert.Equalf(t, len(tc.expectedErrs), len(errs),
"expected %d errors, got %d errors: %v", len(tc.expectedErrs), len(errs), errs,
)
for i, err := range errs {
assert.Equal(t, tc.expectedErrs[i].Error(), err.Error())
}
})
}
}

View File

@@ -29,6 +29,11 @@ import (
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DetectLocalConfiguration) DeepCopyInto(out *DetectLocalConfiguration) {
*out = *in
if in.ClusterCIDRs != nil {
in, out := &in.ClusterCIDRs, &out.ClusterCIDRs
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
@@ -61,7 +66,7 @@ func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) {
in.IPVS.DeepCopyInto(&out.IPVS)
out.Winkernel = in.Winkernel
in.NFTables.DeepCopyInto(&out.NFTables)
out.DetectLocal = in.DetectLocal
in.DetectLocal.DeepCopyInto(&out.DetectLocal)
if in.NodePortAddresses != nil {
in, out := &in.NodePortAddresses, &out.NodePortAddresses
*out = make([]string, len(*in))