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

@@ -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())
}
})
}
}