Skip to content

Commit

Permalink
enable provisioning Gateways that watch specific namespaces (#6073)
Browse files Browse the repository at this point in the history
Adds support to the Gateway provisioner for
configuring Gateways that only watch a subset
of namespaces for resources, when a
ContourDeployment's WatchNamespaces field
is set.

Closes #5256.

Signed-off-by: Lubron Zhan <lubronzhan@gmail.com>
  • Loading branch information
lubronzhan authored Jan 30, 2024
1 parent 54fc8fc commit 29201bb
Show file tree
Hide file tree
Showing 27 changed files with 847 additions and 99 deletions.
21 changes: 21 additions & 0 deletions apis/projectcontour/v1/httpproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@ type HTTPProxySpec struct {
IngressClassName string `json:"ingressClassName,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

// Include describes a set of policies that can be applied to an HTTPProxy in a namespace.
type Include struct {
// Name of the HTTPProxy
Expand Down
22 changes: 22 additions & 0 deletions apis/projectcontour/v1/httpproxy_helpers.go
Original file line number Diff line number Diff line change
@@ -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 v1

func NamespacesToStrings(ns []Namespace) []string {
res := make([]string, len(ns))
for i, n := range ns {
res[i] = string(n)
}
return res
}
46 changes: 46 additions & 0 deletions apis/projectcontour/v1/httpproxy_helpers_test.go
Original file line number Diff line number Diff line change
@@ -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 v1

import (
"reflect"
"testing"
)

func TestNamespacesToStrings(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)
}
})
}
}
9 changes: 9 additions & 0 deletions apis/projectcontour/v1alpha1/contourdeployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package v1alpha1

import (
contour_api_v1 "github.com/projectcontour/contour/apis/projectcontour/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -122,6 +123,14 @@ type ContourSettings struct {
// the annotations for Prometheus will be appended or overwritten with predefined value.
// +optional
PodAnnotations map[string]string `json:"podAnnotations,omitempty"`

// WatchNamespaces is an array of namespaces. Setting it will instruct the contour instance
// to only watch this subset of namespaces.
// +optional
// +kubebuilder:validation:Type=array
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=42
WatchNamespaces []contour_api_v1.Namespace `json:"watchNamespaces,omitempty"`
}

// DeploymentSettings contains settings for Deployment resources.
Expand Down
5 changes: 5 additions & 0 deletions apis/projectcontour/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions changelogs/unreleased/6073-lubronzhan-small.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow gatewayProvisioner to create contour that only watch limited namespaces of resources
22 changes: 22 additions & 0 deletions examples/contour/01-crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1620,6 +1620,28 @@ spec:
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: object
type: object
watchNamespaces:
description: |-
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
type: array
type: object
envoy:
description: |-
Expand Down
22 changes: 22 additions & 0 deletions examples/render/contour-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,28 @@ spec:
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: object
type: object
watchNamespaces:
description: |-
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
type: array
type: object
envoy:
description: |-
Expand Down
22 changes: 22 additions & 0 deletions examples/render/contour-gateway-provisioner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,28 @@ spec:
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: object
type: object
watchNamespaces:
description: |-
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
type: array
type: object
envoy:
description: |-
Expand Down
22 changes: 22 additions & 0 deletions examples/render/contour-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1842,6 +1842,28 @@ spec:
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: object
type: object
watchNamespaces:
description: |-
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
type: array
type: object
envoy:
description: |-
Expand Down
22 changes: 22 additions & 0 deletions examples/render/contour.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,28 @@ spec:
More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
type: object
type: object
watchNamespaces:
description: |-
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
type: array
type: object
envoy:
description: |-
Expand Down
3 changes: 3 additions & 0 deletions internal/provisioner/controller/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"context"
"fmt"

contour_api_v1 "github.com/projectcontour/contour/apis/projectcontour/v1"
contour_api_v1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1"
"github.com/projectcontour/contour/internal/gatewayapi"
"github.com/projectcontour/contour/internal/provisioner/model"
Expand Down Expand Up @@ -261,6 +262,8 @@ func (r *gatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct

contourModel.Spec.KubernetesLogLevel = contourParams.KubernetesLogLevel

contourModel.Spec.WatchNamespaces = contour_api_v1.NamespacesToStrings(contourParams.WatchNamespaces)

if contourParams.Deployment != nil &&
contourParams.Deployment.Strategy != nil {
contourModel.Spec.ContourDeploymentStrategy = *contourParams.Deployment.Strategy
Expand Down
9 changes: 9 additions & 0 deletions internal/provisioner/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ func (c *Contour) EnvoyTolerationsExist() bool {
return false
}

func (c *Contour) WatchAllNamespaces() bool {
return c.Spec.WatchNamespaces == nil || len(c.Spec.WatchNamespaces) == 0
}

// ContourSpec defines the desired state of Contour.
type ContourSpec struct {
// ContourReplicas is the desired number of Contour replicas. If unset,
Expand Down Expand Up @@ -245,6 +249,11 @@ type ContourSpec struct {
// If the value is 0, the overload manager is disabled.
// defaults to 0.
EnvoyMaxHeapSizeBytes uint64

// WatchNamespaces is an array of namespaces. Setting it will instruct the contour instance
// to only watch these set of namespaces
// default is nil, contour will watch resource of all namespaces
WatchNamespaces []string
}

// WorkloadType is the type of Kubernetes workload to use for a component.
Expand Down
16 changes: 10 additions & 6 deletions internal/provisioner/model/names.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ func (c *Contour) ContourRBACNames() RBACNames {
Role: fmt.Sprintf("contour-%s", c.Name),

// this one has a different prefix to differentiate from the certgen role binding (see below).
RoleBinding: fmt.Sprintf("contour-rolebinding-%s", c.Name),
RoleBinding: fmt.Sprintf("contour-rolebinding-%s", c.Name),
NamespaceScopedResourceRole: fmt.Sprintf("contour-resources-%s-%s", c.Namespace, c.Name),
NamespaceScopedResourceRoleBinding: fmt.Sprintf("contour-resources-%s-%s", c.Namespace, c.Name),
}
}

Expand Down Expand Up @@ -129,9 +131,11 @@ func (c *Contour) CommonAnnotations() map[string]string {

// RBACNames holds a set of names of related RBAC resources.
type RBACNames struct {
ServiceAccount string
ClusterRole string
ClusterRoleBinding string
Role string
RoleBinding string
ServiceAccount string
ClusterRole string
ClusterRoleBinding string
Role string
RoleBinding string
NamespaceScopedResourceRole string
NamespaceScopedResourceRoleBinding string
}
10 changes: 10 additions & 0 deletions internal/provisioner/objects/deployment/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"context"
"fmt"
"path/filepath"
"slices"
"strings"

"github.com/projectcontour/contour/apis/projectcontour/v1alpha1"
"github.com/projectcontour/contour/internal/provisioner/equality"
Expand Down Expand Up @@ -100,6 +102,14 @@ func DesiredDeployment(contour *model.Contour, image string) *appsv1.Deployment
args = append(args, "--debug")
}

if !contour.WatchAllNamespaces() {
ns := contour.Spec.WatchNamespaces
if !slices.Contains(contour.Spec.WatchNamespaces, contour.Namespace) {
ns = append(ns, contour.Namespace)
}
args = append(args, fmt.Sprintf("--watch-namespaces=%s", strings.Join(ns, ",")))
}

// Pass the insecure/secure flags to Contour if using non-default ports.
for _, port := range contour.Spec.NetworkPublishing.Envoy.Ports {
switch {
Expand Down
Loading

0 comments on commit 29201bb

Please sign in to comment.