From 80d73efb5a01ca860b08776e38f7e8ab6a28ee96 Mon Sep 17 00:00:00 2001 From: John Gardiner Myers Date: Sat, 30 Oct 2021 16:28:47 -0700 Subject: [PATCH 1/2] Validate CNI can support IPv6 --- pkg/apis/kops/validation/validation.go | 39 +++++++++++++++++-- .../fi/cloudup/populate_cluster_spec_test.go | 2 + 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/pkg/apis/kops/validation/validation.go b/pkg/apis/kops/validation/validation.go index 855c7e7772..235ad6271a 100644 --- a/pkg/apis/kops/validation/validation.go +++ b/pkg/apis/kops/validation/validation.go @@ -671,6 +671,10 @@ func validateNetworking(cluster *kops.Cluster, v *kops.NetworkingSpec, fldPath * if v.Kubenet != nil { optionTaken = true + + if cluster.Spec.IsIPv6Only() { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("kubenet"), "Kubenet does not support IPv6")) + } } if v.External != nil { @@ -685,6 +689,10 @@ func validateNetworking(cluster *kops.Cluster, v *kops.NetworkingSpec, fldPath * allErrs = append(allErrs, field.Forbidden(fldPath.Child("kopeio"), "only one networking option permitted")) } optionTaken = true + + if cluster.Spec.IsIPv6Only() { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("kopeio"), "Kopeio does not support IPv6")) + } } if v.CNI != nil && optionTaken { @@ -696,6 +704,10 @@ func validateNetworking(cluster *kops.Cluster, v *kops.NetworkingSpec, fldPath * allErrs = append(allErrs, field.Forbidden(fldPath.Child("weave"), "only one networking option permitted")) } optionTaken = true + + if cluster.Spec.IsIPv6Only() { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("weave"), "Weave does not support IPv6")) + } } if v.Flannel != nil { @@ -704,7 +716,7 @@ func validateNetworking(cluster *kops.Cluster, v *kops.NetworkingSpec, fldPath * } optionTaken = true - allErrs = append(allErrs, validateNetworkingFlannel(v.Flannel, fldPath.Child("flannel"))...) + allErrs = append(allErrs, validateNetworkingFlannel(cluster, v.Flannel, fldPath.Child("flannel"))...) } if v.Calico != nil { @@ -731,6 +743,10 @@ func validateNetworking(cluster *kops.Cluster, v *kops.NetworkingSpec, fldPath * allErrs = append(allErrs, field.Forbidden(fldPath.Root().Child("spec", "kubeProxy", "enabled"), "kube-router requires kubeProxy to be disabled")) } optionTaken = true + + if cluster.Spec.IsIPv6Only() { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("kuberouter"), "kube-router does not support IPv6")) + } } if v.Romana != nil { @@ -746,6 +762,11 @@ func validateNetworking(cluster *kops.Cluster, v *kops.NetworkingSpec, fldPath * if c.CloudProvider != "aws" { allErrs = append(allErrs, field.Forbidden(fldPath.Child("amazonvpc"), "amazon-vpc-routed-eni networking is supported only in AWS")) } + + if cluster.Spec.IsIPv6Only() { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("amazonvpc"), "amazon-vpc-routed-eni networking does not support IPv6")) + } + } if v.Cilium != nil { @@ -772,9 +793,13 @@ func validateNetworking(cluster *kops.Cluster, v *kops.NetworkingSpec, fldPath * return allErrs } -func validateNetworkingFlannel(v *kops.FlannelNetworkingSpec, fldPath *field.Path) field.ErrorList { +func validateNetworkingFlannel(c *kops.Cluster, v *kops.FlannelNetworkingSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} + if c.Spec.IsIPv6Only() { + allErrs = append(allErrs, field.Forbidden(fldPath, "Flannel does not support IPv6")) + } + if v.Backend == "" { allErrs = append(allErrs, field.Required(fldPath.Child("backend"), "Flannel backend must be specified")) } else { @@ -787,6 +812,10 @@ func validateNetworkingFlannel(v *kops.FlannelNetworkingSpec, fldPath *field.Pat func validateNetworkingCanal(c *kops.Cluster, v *kops.CanalNetworkingSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} + if c.Spec.IsIPv6Only() { + allErrs = append(allErrs, field.Forbidden(fldPath, "Canal does not support IPv6")) + } + if v.DefaultEndpointToHostAction != "" { valid := []string{"ACCEPT", "DROP", "RETURN"} allErrs = append(allErrs, IsValidValue(fldPath.Child("defaultEndpointToHostAction"), &v.DefaultEndpointToHostAction, valid)...) @@ -930,7 +959,11 @@ func validateNetworkingGCE(c *kops.ClusterSpec, v *kops.GCENetworkingSpec, fldPa allErrs := field.ErrorList{} if c.CloudProvider != "gce" { - allErrs = append(allErrs, field.Forbidden(fldPath, "gce networking is supported only when on GCP")) + allErrs = append(allErrs, field.Forbidden(fldPath, "GCE networking is supported only when on GCP")) + } + + if c.IsIPv6Only() { + allErrs = append(allErrs, field.Forbidden(fldPath, "GCE networking does not support IPv6")) } return allErrs diff --git a/upup/pkg/fi/cloudup/populate_cluster_spec_test.go b/upup/pkg/fi/cloudup/populate_cluster_spec_test.go index 904ee6455f..bf4dfb5d5f 100644 --- a/upup/pkg/fi/cloudup/populate_cluster_spec_test.go +++ b/upup/pkg/fi/cloudup/populate_cluster_spec_test.go @@ -85,6 +85,8 @@ func TestPopulateCluster_Subnets(t *testing.T) { t.Run(tc.NonMasqueradeCIDR, func(t *testing.T) { cloud, c := buildMinimalCluster() c.Spec.NonMasqueradeCIDR = tc.NonMasqueradeCIDR + c.Spec.Networking.Kubenet = nil + c.Spec.Networking.CNI = &kopsapi.CNINetworkingSpec{} err := PerformAssignments(c, cloud) require.NoError(t, err, "PerformAssignments") From a50047cacb0ba7999a379905b7ccc49e72b1404b Mon Sep 17 00:00:00 2001 From: John Gardiner Myers Date: Sat, 30 Oct 2021 16:47:37 -0700 Subject: [PATCH 2/2] Fix Calico encapsulationMode validation error types --- pkg/apis/kops/validation/validation.go | 13 +++++++------ pkg/apis/kops/validation/validation_test.go | 12 ++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/pkg/apis/kops/validation/validation.go b/pkg/apis/kops/validation/validation.go index 235ad6271a..5b6bd26411 100644 --- a/pkg/apis/kops/validation/validation.go +++ b/pkg/apis/kops/validation/validation.go @@ -1143,17 +1143,18 @@ func validateNetworkingCalico(c *kops.ClusterSpec, v *kops.CalicoNetworkingSpec, } if v.EncapsulationMode != "" { - if c.IsIPv6Only() { + valid := []string{"ipip", "vxlan", "none"} + allErrs = append(allErrs, IsValidValue(fldPath.Child("encapsulationMode"), &v.EncapsulationMode, valid)...) + + if v.EncapsulationMode != "none" && c.IsIPv6Only() { // IPv6 doesn't support encapsulation and kops only uses the "none" networking backend. // The bird networking backend could also be added in the future if there's any valid use case. - valid := []string{"none"} - allErrs = append(allErrs, IsValidValue(fldPath.Child("encapsulationMode"), &v.EncapsulationMode, valid)...) - } else { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("encapsulationMode"), "IPv6 requires an encapsulationMode of \"none\"")) + } else if v.EncapsulationMode == "none" && !c.IsIPv6Only() { // Don't tolerate "None" for now, which would disable encapsulation in the default IPPool // object. Note that with no encapsulation, we'd need to select the "bird" networking // backend in order to allow use of BGP to distribute routes for pod traffic. - valid := []string{"ipip", "vxlan"} - allErrs = append(allErrs, IsValidValue(fldPath.Child("encapsulationMode"), &v.EncapsulationMode, valid)...) + allErrs = append(allErrs, field.Forbidden(fldPath.Child("encapsulationMode"), "encapsulationMode \"none\" is only supported for IPv6 clusters")) } } diff --git a/pkg/apis/kops/validation/validation_test.go b/pkg/apis/kops/validation/validation_test.go index bcafe32c53..28379cad85 100644 --- a/pkg/apis/kops/validation/validation_test.go +++ b/pkg/apis/kops/validation/validation_test.go @@ -626,7 +626,7 @@ func Test_Validate_Calico(t *testing.T) { }, }, { - Description: "unknown Calico encapsulation mode", + Description: "encapsulation none with IPv4", Input: caliInput{ Cluster: &kops.ClusterSpec{ NonMasqueradeCIDR: "100.64.0.0/10", @@ -635,10 +635,10 @@ func Test_Validate_Calico(t *testing.T) { EncapsulationMode: "none", }, }, - ExpectedErrors: []string{"Unsupported value::calico.encapsulationMode"}, + ExpectedErrors: []string{"Forbidden::calico.encapsulationMode"}, }, { - Description: "unknown Calico encapsulation mode IPIP for IPv6", + Description: "encapsulation mode IPIP for IPv6", Input: caliInput{ Cluster: &kops.ClusterSpec{ NonMasqueradeCIDR: "::/0", @@ -647,10 +647,10 @@ func Test_Validate_Calico(t *testing.T) { EncapsulationMode: "ipip", }, }, - ExpectedErrors: []string{"Unsupported value::calico.encapsulationMode"}, + ExpectedErrors: []string{"Forbidden::calico.encapsulationMode"}, }, { - Description: "unknown Calico encapsulation mode VXLAN for IPv6", + Description: "encapsulation mode VXLAN for IPv6", Input: caliInput{ Cluster: &kops.ClusterSpec{ NonMasqueradeCIDR: "::/0", @@ -659,7 +659,7 @@ func Test_Validate_Calico(t *testing.T) { EncapsulationMode: "vxlan", }, }, - ExpectedErrors: []string{"Unsupported value::calico.encapsulationMode"}, + ExpectedErrors: []string{"Forbidden::calico.encapsulationMode"}, }, { Description: "unknown Calico IPIP mode",