Skip to content

Commit

Permalink
internal/dag: Watch namespaces from k8s api (#3402)
Browse files Browse the repository at this point in the history
The RouteBindingSelector in Gateway API has an option to only process routes which exist
in a namespace based upon a selector defined in the Gateway.

When "Selector" is chosen then only Routes in namespaces selected by the selector may be used by this Gateway (https://gateway-api.sigs.k8s.io/spec/#networking.x-k8s.io/v1alpha1.RouteSelectType).

Updates #3401

Signed-off-by: Steve Sloka <slokas@vmware.com>
  • Loading branch information
stevesloka committed Mar 1, 2021
1 parent 4eea15d commit 9fc4431
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 0 deletions.
10 changes: 10 additions & 0 deletions cmd/contour/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,17 +471,27 @@ func doServe(log logrus.FieldLogger, ctx *serveContext) error {
if ctx.UseExperimentalServiceAPITypes {
log.Warn("DEPRECATED: The flag '--experimental-service-apis' is deprecated and should not be used. Please configure the gateway.name & gateway.namespace in the configuration file to specify which Gateway Contour will be watching.")
}

foundGatewayAPI := false
for _, r := range k8s.GatewayAPIResources() {
if !clients.ResourcesExist(r) {
log.WithField("resource", r).Warn("resource type not present on API server")
continue
}
foundGatewayAPI = true

if err := informOnResource(clients, r, &dynamicHandler); err != nil {
log.WithError(err).WithField("resource", r).Fatal("failed to create informer")
}
}

// Only watch namespaces if Gateway API is found.
if foundGatewayAPI {
if err := informOnResource(clients, k8s.NamespacesResource(), &dynamicHandler); err != nil {
log.WithError(err).WithField("resource", k8s.NamespacesResource()).Fatal("failed to create informer")
}
}

// Inform on secrets, filtering by root namespaces.
for _, r := range k8s.SecretsResources() {
var handler cache.ResourceEventHandler = &dynamicHandler
Expand Down
8 changes: 8 additions & 0 deletions examples/contour/02-role-contour.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ rules:
- get
- list
- watch
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
Expand Down
8 changes: 8 additions & 0 deletions examples/render/contour.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1824,6 +1824,14 @@ rules:
- get
- list
- watch
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
Expand Down
10 changes: 10 additions & 0 deletions internal/dag/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type KubernetesCache struct {
secrets map[types.NamespacedName]*v1.Secret
httpproxydelegations map[types.NamespacedName]*contour_api_v1.TLSCertificateDelegation
services map[types.NamespacedName]*v1.Service
namespaces map[types.NamespacedName]*v1.Namespace
gateway *gatewayapi_v1alpha1.Gateway
httproutes map[types.NamespacedName]*gatewayapi_v1alpha1.HTTPRoute
tlsroutes map[types.NamespacedName]*gatewayapi_v1alpha1.TLSRoute
Expand All @@ -76,6 +77,7 @@ func (kc *KubernetesCache) init() {
kc.secrets = make(map[types.NamespacedName]*v1.Secret)
kc.httpproxydelegations = make(map[types.NamespacedName]*contour_api_v1.TLSCertificateDelegation)
kc.services = make(map[types.NamespacedName]*v1.Service)
kc.namespaces = make(map[types.NamespacedName]*v1.Namespace)
kc.httproutes = make(map[types.NamespacedName]*gatewayapi_v1alpha1.HTTPRoute)
kc.tlsroutes = make(map[types.NamespacedName]*gatewayapi_v1alpha1.TLSRoute)
kc.backendpolicies = make(map[types.NamespacedName]*gatewayapi_v1alpha1.BackendPolicy)
Expand Down Expand Up @@ -167,6 +169,9 @@ func (kc *KubernetesCache) Insert(obj interface{}) bool {
case *v1.Service:
kc.services[k8s.NamespacedNameOf(obj)] = obj
return kc.serviceTriggersRebuild(obj)
case *v1.Namespace:
kc.namespaces[k8s.NamespacedNameOf(obj)] = obj
return true
case *v1beta1.Ingress:
if kc.matchesIngressClass(obj) {
// Convert the v1beta1 object to v1 before adding to the
Expand Down Expand Up @@ -346,6 +351,11 @@ func (kc *KubernetesCache) remove(obj interface{}) bool {
_, ok := kc.services[m]
delete(kc.services, m)
return ok
case *v1.Namespace:
m := k8s.NamespacedNameOf(obj)
_, ok := kc.namespaces[m]
delete(kc.namespaces, m)
return ok
case *v1beta1.Ingress:
m := k8s.NamespacedNameOf(obj)
_, ok := kc.ingresses[m]
Expand Down
24 changes: 24 additions & 0 deletions internal/dag/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,15 @@ func TestKubernetesCacheInsert(t *testing.T) {
},
want: true,
},
"insert namespace": {
obj: &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "namespace",
Namespace: "default",
},
},
want: true,
},
"insert gateway-api Gateway": {
obj: &gatewayapi_v1alpha1.Gateway{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -787,6 +796,21 @@ func TestKubernetesCacheRemove(t *testing.T) {
},
want: true,
},
"remove namespace": {
cache: cache(&v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "namespace",
Namespace: "default",
},
}),
obj: &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "namespace",
Namespace: "default",
},
},
want: true,
},
"remove ingress": {
cache: cache(&v1beta1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Expand Down
7 changes: 7 additions & 0 deletions internal/k8s/informers.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,10 @@ func ServicesResources() []schema.GroupVersionResource {
corev1.SchemeGroupVersion.WithResource("services"),
}
}

// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch

// NamespacesResource ...
func NamespacesResource() schema.GroupVersionResource {
return corev1.SchemeGroupVersion.WithResource("namespaces")
}

0 comments on commit 9fc4431

Please sign in to comment.