From c8666adf6dc6e79f1e589eb52e6350eb2d0f07ee Mon Sep 17 00:00:00 2001 From: Lubron Zhan Date: Thu, 25 Jan 2024 16:24:03 -0800 Subject: [PATCH] Add namespace alias for string for validation purpose Signed-off-by: Lubron Zhan --- .../v1alpha1/contourdeployment.go | 24 +++++++++- .../v1alpha1/contourdeployment_helpers.go | 22 +++++++++ .../contourdeployment_helpers_test.go | 46 +++++++++++++++++++ .../v1alpha1/zz_generated.deepcopy.go | 2 +- examples/contour/01-crds.yaml | 13 ++++++ examples/render/contour-deployment.yaml | 13 ++++++ .../render/contour-gateway-provisioner.yaml | 13 ++++++ examples/render/contour-gateway.yaml | 13 ++++++ examples/render/contour.yaml | 13 ++++++ internal/provisioner/controller/gateway.go | 2 +- .../objects/deployment/deployment_test.go | 7 +-- .../docs/main/config/api-reference.html | 25 +++++++++- test/e2e/provisioner/provisioner_test.go | 6 +-- 13 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 apis/projectcontour/v1alpha1/contourdeployment_helpers.go create mode 100644 apis/projectcontour/v1alpha1/contourdeployment_helpers_test.go diff --git a/apis/projectcontour/v1alpha1/contourdeployment.go b/apis/projectcontour/v1alpha1/contourdeployment.go index 1021689c696..e08b1fd6272 100644 --- a/apis/projectcontour/v1alpha1/contourdeployment.go +++ b/apis/projectcontour/v1alpha1/contourdeployment.go @@ -75,6 +75,27 @@ type ContourDeploymentSpec struct { ResourceLabels map[string]string `json:"resourceLabels,omitempty"` } +// Namespace refers to a Kubernetes namespace. It must be a RFC 1123 label. +// +// This validation is based off of the corresponding Kubernetes validation: +// https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L187 +// +// This is used for Namespace name validation here: +// https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/api/validation/generic.go#L63 +// +// Valid values include: +// +// * "example" +// +// Invalid values include: +// +// * "example.com" - "." is an invalid character +// +// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$` +// +kubebuilder:validation:MinLength=1 +// +kubebuilder:validation:MaxLength=63 +type Namespace string + // ContourSettings contains settings for the Contour part of the installation, // i.e. the xDS server/control plane and associated resources. type ContourSettings struct { @@ -127,10 +148,9 @@ type ContourSettings struct { // to only watch this subset of namespaces. // +optional // +kubebuilder:validation:Type=array - // +kubebuilder:validation:Items=string // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=42 - WatchNamespaces []string `json:"watchNamespaces,omitempty"` + WatchNamespaces []Namespace `json:"watchNamespaces,omitempty"` } // DeploymentSettings contains settings for Deployment resources. diff --git a/apis/projectcontour/v1alpha1/contourdeployment_helpers.go b/apis/projectcontour/v1alpha1/contourdeployment_helpers.go new file mode 100644 index 00000000000..947910c38d3 --- /dev/null +++ b/apis/projectcontour/v1alpha1/contourdeployment_helpers.go @@ -0,0 +1,22 @@ +// Copyright Project Contour 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 v1alpha1 + +func NamespacesToStrings(ns []Namespace) []string { + res := make([]string, len(ns)) + for i, n := range ns { + res[i] = string(n) + } + return res +} diff --git a/apis/projectcontour/v1alpha1/contourdeployment_helpers_test.go b/apis/projectcontour/v1alpha1/contourdeployment_helpers_test.go new file mode 100644 index 00000000000..0d34c640536 --- /dev/null +++ b/apis/projectcontour/v1alpha1/contourdeployment_helpers_test.go @@ -0,0 +1,46 @@ +// Copyright Project Contour 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 v1alpha1 + +import ( + "reflect" + "testing" +) + +func TestDesiredRoleBindingInNamespace(t *testing.T) { + testCases := []struct { + description string + namespaces []Namespace + expectStrings []string + }{ + { + description: "namespace 1", + namespaces: []Namespace{}, + expectStrings: []string{}, + }, + { + description: "namespace 2", + namespaces: []Namespace{"ns1", "ns2"}, + expectStrings: []string{"ns1", "ns2"}, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + if !reflect.DeepEqual(NamespacesToStrings(tc.namespaces), tc.expectStrings) { + t.Errorf("expect converted strings %v is the same as %v", NamespacesToStrings(tc.namespaces), tc.expectStrings) + } + }) + } +} diff --git a/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go b/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go index 3d3e0acc50d..0f5917acf1a 100644 --- a/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go +++ b/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go @@ -389,7 +389,7 @@ func (in *ContourSettings) DeepCopyInto(out *ContourSettings) { } if in.WatchNamespaces != nil { in, out := &in.WatchNamespaces, &out.WatchNamespaces - *out = make([]string, len(*in)) + *out = make([]Namespace, len(*in)) copy(*out, *in) } } diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml index ed003075c50..adf820dabc2 100644 --- a/examples/contour/01-crds.yaml +++ b/examples/contour/01-crds.yaml @@ -1625,6 +1625,19 @@ spec: WatchNamespaces is an array of namespaces. Setting it will instruct the contour instance to only watch this subset of namespaces. items: + description: |- + Namespace refers to a Kubernetes namespace. It must be a RFC 1123 label. + This validation is based off of the corresponding Kubernetes validation: + https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L187 + This is used for Namespace name validation here: + https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/api/validation/generic.go#L63 + Valid values include: + * "example" + Invalid values include: + * "example.com" - "." is an invalid character + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string maxItems: 42 minItems: 1 diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml index 9c49d4abc30..176896adb04 100644 --- a/examples/render/contour-deployment.yaml +++ b/examples/render/contour-deployment.yaml @@ -1844,6 +1844,19 @@ spec: WatchNamespaces is an array of namespaces. Setting it will instruct the contour instance to only watch this subset of namespaces. items: + description: |- + Namespace refers to a Kubernetes namespace. It must be a RFC 1123 label. + This validation is based off of the corresponding Kubernetes validation: + https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L187 + This is used for Namespace name validation here: + https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/api/validation/generic.go#L63 + Valid values include: + * "example" + Invalid values include: + * "example.com" - "." is an invalid character + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string maxItems: 42 minItems: 1 diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml index efc40769988..08760885e9d 100644 --- a/examples/render/contour-gateway-provisioner.yaml +++ b/examples/render/contour-gateway-provisioner.yaml @@ -1636,6 +1636,19 @@ spec: WatchNamespaces is an array of namespaces. Setting it will instruct the contour instance to only watch this subset of namespaces. items: + description: |- + Namespace refers to a Kubernetes namespace. It must be a RFC 1123 label. + This validation is based off of the corresponding Kubernetes validation: + https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L187 + This is used for Namespace name validation here: + https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/api/validation/generic.go#L63 + Valid values include: + * "example" + Invalid values include: + * "example.com" - "." is an invalid character + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string maxItems: 42 minItems: 1 diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml index 1b1b38f18f6..b985b1307e6 100644 --- a/examples/render/contour-gateway.yaml +++ b/examples/render/contour-gateway.yaml @@ -1847,6 +1847,19 @@ spec: WatchNamespaces is an array of namespaces. Setting it will instruct the contour instance to only watch this subset of namespaces. items: + description: |- + Namespace refers to a Kubernetes namespace. It must be a RFC 1123 label. + This validation is based off of the corresponding Kubernetes validation: + https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L187 + This is used for Namespace name validation here: + https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/api/validation/generic.go#L63 + Valid values include: + * "example" + Invalid values include: + * "example.com" - "." is an invalid character + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string maxItems: 42 minItems: 1 diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml index 7e424cc7e9e..3c25df955bd 100644 --- a/examples/render/contour.yaml +++ b/examples/render/contour.yaml @@ -1844,6 +1844,19 @@ spec: WatchNamespaces is an array of namespaces. Setting it will instruct the contour instance to only watch this subset of namespaces. items: + description: |- + Namespace refers to a Kubernetes namespace. It must be a RFC 1123 label. + This validation is based off of the corresponding Kubernetes validation: + https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L187 + This is used for Namespace name validation here: + https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/api/validation/generic.go#L63 + Valid values include: + * "example" + Invalid values include: + * "example.com" - "." is an invalid character + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string maxItems: 42 minItems: 1 diff --git a/internal/provisioner/controller/gateway.go b/internal/provisioner/controller/gateway.go index 3b004adbd20..b8822c0c758 100644 --- a/internal/provisioner/controller/gateway.go +++ b/internal/provisioner/controller/gateway.go @@ -261,7 +261,7 @@ func (r *gatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct contourModel.Spec.KubernetesLogLevel = contourParams.KubernetesLogLevel - contourModel.Spec.WatchNamespaces = contourParams.WatchNamespaces + contourModel.Spec.WatchNamespaces = contour_api_v1alpha1.NamespacesToStrings(contourParams.WatchNamespaces) if contourParams.Deployment != nil && contourParams.Deployment.Strategy != nil { diff --git a/internal/provisioner/objects/deployment/deployment_test.go b/internal/provisioner/objects/deployment/deployment_test.go index c008f3bae43..cd0b9ee4d96 100644 --- a/internal/provisioner/objects/deployment/deployment_test.go +++ b/internal/provisioner/objects/deployment/deployment_test.go @@ -236,14 +236,9 @@ func TestDesiredDeploymentWhenSettingWatchNamespaces(t *testing.T) { }, { description: "single valid namespace", - namespaces: []string{"ns1", "ns2"}, + namespaces: []string{"ns1"}, expectArgExist: true, }, - { - description: "include empty namespace", - namespaces: []string{"ns1", ""}, - expectArgExist: false, - }, } for _, tc := range testCases { diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html index dad878165fc..1e452f97bf5 100644 --- a/site/content/docs/main/config/api-reference.html +++ b/site/content/docs/main/config/api-reference.html @@ -6252,7 +6252,9 @@

ContourSettings watchNamespaces
-[]string + +[]Namespace + @@ -8094,6 +8096,27 @@

MetricsTLS +

Namespace +(string alias)

+

+(Appears on: +ContourSettings) +

+

+

Namespace refers to a Kubernetes namespace. It must be a RFC 1123 label.

+

This validation is based off of the corresponding Kubernetes validation: +https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L187

+

This is used for Namespace name validation here: +https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/api/validation/generic.go#L63

+

Valid values include:

+ +

Invalid values include:

+ +

NamespacedName

diff --git a/test/e2e/provisioner/provisioner_test.go b/test/e2e/provisioner/provisioner_test.go index d00c64483c9..4c0016527d3 100644 --- a/test/e2e/provisioner/provisioner_test.go +++ b/test/e2e/provisioner/provisioner_test.go @@ -519,7 +519,7 @@ var _ = Describe("Gateway provisioner", func() { Spec: contour_api_v1alpha1.ContourDeploymentSpec{ RuntimeSettings: contourDeploymentRuntimeSettings(), Contour: &contour_api_v1alpha1.ContourSettings{ - WatchNamespaces: []string{"testns-1", "testns-2"}, + WatchNamespaces: []contour_api_v1alpha1.Namespace{"testns-1", "testns-2"}, }, }, } @@ -572,7 +572,7 @@ var _ = Describe("Gateway provisioner", func() { gateway, ok := f.CreateGatewayAndWaitFor(gateway, func(gw *gatewayapi_v1beta1.Gateway) bool { return e2e.GatewayProgrammed(gw) && e2e.GatewayHasAddress(gw) }) - require.True(f.T(), ok) + require.True(f.T(), ok, fmt.Sprintf("gateway is %v", gateway)) type testObj struct { expectReconcile bool namespace string @@ -626,7 +626,7 @@ var _ = Describe("Gateway provisioner", func() { By(fmt.Sprintf("Expect namespace %s to be watched by contour", t.namespace)) hr, ok := f.CreateHTTPRouteAndWaitFor(route, e2e.HTTPRouteAccepted) By(fmt.Sprintf("Expect httproute under namespace %s is accepted", t.namespace)) - require.True(f.T(), ok, fmt.Sprintf("httproute's is %v", hr)) + require.True(f.T(), ok, fmt.Sprintf("httproute is %v", hr)) res, ok := f.HTTP.RequestUntil(&e2e.HTTPRequestOpts{ OverrideURL: "http://" + net.JoinHostPort(gateway.Status.Addresses[0].Value, "80"), Host: string(route.Spec.Hostnames[0]),