Skip to content

Commit

Permalink
addressed review comments - 1
Browse files Browse the repository at this point in the history
Signed-off-by: Shubham Chauhan <shubham@tetrate.io>

predicates pt1

Signed-off-by: Shubham Chauhan <shubham@tetrate.io>
  • Loading branch information
chauhanshubham committed Nov 30, 2022
1 parent 5480e4a commit 0711567
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 58 deletions.
4 changes: 2 additions & 2 deletions api/config/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

// Package v1alpha1 contains API Schema definitions for the config v1alpha1 API group.
//
// +kubebuilder:object:generate=true
// +groupName=config.gateway.envoyproxy.io
//+kubebuilder:object:generate=true
//+groupName=config.gateway.envoyproxy.io
package v1alpha1

import (
Expand Down
92 changes: 40 additions & 52 deletions internal/provider/kubernetes/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,23 +84,34 @@ func newGatewayAPIController(mgr manager.Manager, cfg *config.Server, su status.
}

// Watch Gateway CRUDs and reconcile affected GatewayClass.
if err := c.Watch(&source.Kind{Type: &gwapiv1b1.Gateway{}}, &handler.EnqueueRequestForObject{}); err != nil {
if err := c.Watch(
&source.Kind{Type: &gwapiv1b1.Gateway{}},
&handler.EnqueueRequestForObject{},
predicate.NewPredicateFuncs(r.validateGatewayForReconcile)); err != nil {
return err
}
if err := addGatewayIndexers(ctx, mgr); err != nil {
return err
}

// Watch HTTPRoute CRUDs and process affected Gateways.
if err := c.Watch(&source.Kind{Type: &gwapiv1b1.HTTPRoute{}}, &handler.EnqueueRequestForObject{}); err != nil {
if err := c.Watch(
&source.Kind{Type: &gwapiv1b1.HTTPRoute{}},
&handler.EnqueueRequestForObject{},
predicate.NewPredicateFuncs(r.validateHTTPRouteForReconcile),
); err != nil {
return err
}
if err := addHTTPRouteIndexers(ctx, mgr); err != nil {
return err
}

// Watch TLSRoute CRUDs and process affected Gateways.
if err := c.Watch(&source.Kind{Type: &gwapiv1a2.TLSRoute{}}, &handler.EnqueueRequestForObject{}); err != nil {
if err := c.Watch(
&source.Kind{Type: &gwapiv1a2.TLSRoute{}},
&handler.EnqueueRequestForObject{},
predicate.NewPredicateFuncs(r.validateTLSRouteForReconcile),
); err != nil {
return err
}
if err := addTLSRouteIndexers(ctx, mgr); err != nil {
Expand Down Expand Up @@ -144,22 +155,21 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, request reconcile.

var cc controlledClasses

for i := range gatewayClasses.Items {
gwClass := gatewayClasses.Items[i].DeepCopy()
for _, gwClass := range gatewayClasses.Items {
if gwClass.Spec.ControllerName == r.classController {
// The gatewayclass was marked for deletion and the finalizer removed,
// so clean-up dependents.
if !gwClass.DeletionTimestamp.IsZero() &&
!slice.ContainsString(gwClass.Finalizers, gatewayClassFinalizer) {
r.log.Info("gatewayclass marked for deletion")
cc.removeMatch(gwClass)
cc.removeMatch(&gwClass)

// Delete the gatewayclass from the watchable map.
r.resources.GatewayAPIResources.Delete(gwClass.Name)
continue
}

cc.addMatch(gwClass)
cc.addMatch(&gwClass)
}
}

Expand Down Expand Up @@ -231,22 +241,15 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, request reconcile.
return reconcile.Result{}, err
}

for i := range gatewayList.Items {
gtw := gatewayList.Items[i].DeepCopy()
for _, gtw := range gatewayList.Items {
r.log.Info("processing Gateway", "namespace", gtw.Namespace, "name", gtw.Name)
allAssociatedNamespaces[gtw.Namespace] = struct{}{}

if gtw.Spec.Listeners == nil {
continue
}

for l := range gtw.Spec.Listeners {
listener := gtw.Spec.Listeners[l].DeepCopy()
for _, listener := range gtw.Spec.Listeners {
// Get Secret for gateway if it exists.
if terminatesTLS(listener) {
for c := range listener.TLS.CertificateRefs {
certRef := listener.TLS.CertificateRefs[c].DeepCopy()
if refsSecret(certRef) {
if terminatesTLS(&listener) {
for _, certRef := range listener.TLS.CertificateRefs {
if refsSecret(&certRef) {
secret := new(corev1.Secret)
secretNamespace := gatewayapi.NamespaceDerefOr(certRef.Namespace, gtw.Namespace)
err := r.client.Get(ctx,
Expand All @@ -269,11 +272,11 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, request reconcile.
continue
}

resourceTree.ReferenceGrants = append(resourceTree.ReferenceGrants, refGrant.DeepCopy())
resourceTree.ReferenceGrants = append(resourceTree.ReferenceGrants, refGrant)
}

allAssociatedNamespaces[secretNamespace] = struct{}{}
resourceTree.Secrets = append(resourceTree.Secrets, secret.DeepCopy())
resourceTree.Secrets = append(resourceTree.Secrets, secret)
}
}
}
Expand All @@ -283,7 +286,7 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, request reconcile.
// Get TLSRoute objects and check if it exists.
tlsRouteList := &gwapiv1a2.TLSRouteList{}
if err := r.client.List(ctx, tlsRouteList, &client.ListOptions{
FieldSelector: fields.OneTermEqualSelector(gatewayTLSRouteIndex, utils.NamespacedName(gtw).String()),
FieldSelector: fields.OneTermEqualSelector(gatewayTLSRouteIndex, utils.NamespacedName(&gtw).String()),
}); err != nil {
r.log.Error(err, "unable to find associated TLSRoutes")
return reconcile.Result{}, err
Expand Down Expand Up @@ -314,19 +317,19 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, request reconcile.
continue
}

resourceTree.ReferenceGrants = append(resourceTree.ReferenceGrants, refGrant.DeepCopy())
resourceTree.ReferenceGrants = append(resourceTree.ReferenceGrants, refGrant)
}
}
}

allAssociatedNamespaces[tlsRoute.Namespace] = struct{}{}
resourceTree.TLSRoutes = append(resourceTree.TLSRoutes, tlsRoute.DeepCopy())
resourceTree.TLSRoutes = append(resourceTree.TLSRoutes, &tlsRoute)
}

// Get HTTPRoute objects and check if it exists.
httpRouteList := &gwapiv1b1.HTTPRouteList{}
if err := r.client.List(ctx, httpRouteList, &client.ListOptions{
FieldSelector: fields.OneTermEqualSelector(gatewayHTTPRouteIndex, utils.NamespacedName(gtw).String()),
FieldSelector: fields.OneTermEqualSelector(gatewayHTTPRouteIndex, utils.NamespacedName(&gtw).String()),
}); err != nil {
r.log.Error(err, "unable to find associated HTTPRoutes")
return reconcile.Result{}, err
Expand Down Expand Up @@ -356,13 +359,13 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, request reconcile.
continue
}

resourceTree.ReferenceGrants = append(resourceTree.ReferenceGrants, refGrant.DeepCopy())
resourceTree.ReferenceGrants = append(resourceTree.ReferenceGrants, refGrant)
}
}
}

allAssociatedNamespaces[httpRoute.Namespace] = struct{}{}
resourceTree.HTTPRoutes = append(resourceTree.HTTPRoutes, httpRoute.DeepCopy())
resourceTree.HTTPRoutes = append(resourceTree.HTTPRoutes, &httpRoute)
}

for serviceNamespaceName := range routeServicesList {
Expand All @@ -380,7 +383,7 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, request reconcile.
}

allAssociatedNamespaces[service.Namespace] = struct{}{}
resourceTree.Services = append(resourceTree.Services, service.DeepCopy())
resourceTree.Services = append(resourceTree.Services, service)
}
}

Expand All @@ -396,10 +399,10 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, request reconcile.
return reconcile.Result{}, err
}

resourceTree.Namespaces = append(resourceTree.Namespaces, namespace.DeepCopy())
resourceTree.Namespaces = append(resourceTree.Namespaces, namespace)
}

resourceTree.Gateways = append(resourceTree.Gateways, gtw)
resourceTree.Gateways = append(resourceTree.Gateways, &gtw)
}

if err := updater(acceptedGC, true); err != nil {
Expand Down Expand Up @@ -431,7 +434,7 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, request reconcile.

r.resources.GatewayAPIResources.Store(acceptedGC.Name, resourceTree)

r.log.WithName(request.Name).Info("reconciled successfully")
r.log.WithName(request.Name).Info("reconciled gatewayAPI object successfully", "namespace", request.Namespace, "name", request.Name)
return reconcile.Result{}, nil
}

Expand All @@ -445,8 +448,9 @@ func (r *gatewayAPIReconciler) getNamespace(ctx context.Context, name string) (*
return ns, nil
}

// enqueueRequestForOwningGateway returns an event handler that maps events for
// resources with Gateway owning labels to reconcile requests for those Gateway objects.
// processDeploymentForOwningGateway tries finding the owning Gateway of the Deployment
// if it exists, finds the Gateway's Service, and further updates the Gateway
// status Ready condition.
func (r *gatewayAPIReconciler) processDeploymentForOwningGateway(obj client.Object) (request []reconcile.Request) {
// Process Deployment Reconcile nothing.
ctx := context.Background()
Expand Down Expand Up @@ -474,6 +478,9 @@ func (r *gatewayAPIReconciler) processDeploymentForOwningGateway(obj client.Obje
return
}

// processServiceForOwningGateway tries finding the owning Gateway of the Service
// if it exists, finds the Gateway's Deployment, and further updates the Gateway
// status Ready condition.
func (r *gatewayAPIReconciler) processServiceForOwningGateway(obj client.Object) (request []reconcile.Request) {
// Process Service Reconcile nothing.
ctx := context.Background()
Expand Down Expand Up @@ -637,25 +644,6 @@ func addTLSRouteIndexers(ctx context.Context, mgr manager.Manager) error {
return nil
}

// hasMatchingController returns true if the provided object is a GatewayClass
// with a Spec.Controller string matching this Envoy Gateway's controller string,
// or false otherwise.
func (r *gatewayAPIReconciler) hasMatchingController(obj client.Object) bool {
gc, ok := obj.(*gwapiv1b1.GatewayClass)
if !ok {
r.log.Info("bypassing reconciliation due to unexpected object type", "type", obj)
return false
}

if gc.Spec.ControllerName == r.classController {
r.log.Info("gatewayclass has matching controller name, processing", "name", gc.Name)
return true
}

r.log.Info("bypassing reconciliation due to controller name", "controller", gc.Spec.ControllerName)
return false
}

// addGatewayIndexers adds indexing on Gateway, for Secret objects that are
// referenced in Gateway objects. This helps in querying for Gateways that are
// affected by a particular Secret CRUD.
Expand Down
105 changes: 105 additions & 0 deletions internal/provider/kubernetes/predicates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright Envoy Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.

package kubernetes

import (
"context"

"github.com/envoyproxy/gateway/internal/gatewayapi"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1"
)

// hasMatchingController returns true if the provided object is a GatewayClass
// with a Spec.Controller string matching this Envoy Gateway's controller string,
// or false otherwise.
func (r *gatewayAPIReconciler) hasMatchingController(obj client.Object) bool {
gc, ok := obj.(*gwapiv1b1.GatewayClass)
if !ok {
r.log.Info("bypassing reconciliation due to unexpected object type", "type", obj)
return false
}

if gc.Spec.ControllerName == r.classController {
r.log.Info("gatewayclass has matching controller name, processing", "name", gc.Name)
return true
}

r.log.Info("bypassing reconciliation due to controller name", "controller", gc.Spec.ControllerName)
return false
}

// validateGatewayForReconcile returns true if the provided object is a Gateway
// using a GatewayClass matching the configured gatewayclass controller name.
func (r *gatewayAPIReconciler) validateGatewayForReconcile(obj client.Object) bool {
gw, ok := obj.(*gwapiv1b1.Gateway)
if !ok {
r.log.Info("unexpected object type, bypassing reconciliation", "object", obj)
return false
}

gc := &gwapiv1b1.GatewayClass{}
key := types.NamespacedName{Name: string(gw.Spec.GatewayClassName)}
if err := r.client.Get(context.Background(), key, gc); err != nil {
r.log.Error(err, "failed to get gatewayclass", "name", gw.Spec.GatewayClassName)
return false
}

if gc.Spec.ControllerName != r.classController {
r.log.Info("gatewayclass name for gateway doesn't match configured name",
"namespace", gw.Namespace, "name", gw.Name)
return false
}

return true
}

func (r *gatewayAPIReconciler) validateHTTPRouteForReconcile(obj client.Object) bool {
hr, ok := obj.(*gwapiv1b1.HTTPRoute)
if !ok {
r.log.Info("unexpected object type, bypassing reconciliation", "object", obj)
return false
}

parentReferences := hr.Spec.ParentRefs
return r.validateRouteParentReferences(parentReferences, hr.Namespace)
}

func (r *gatewayAPIReconciler) validateTLSRouteForReconcile(obj client.Object) bool {
tr, ok := obj.(*gwapiv1a2.TLSRoute)
if !ok {
r.log.Info("unexpected object type, bypassing reconciliation", "object", obj)
return false
}

parentReferences := gatewayapi.UpgradeParentReferences(tr.Spec.ParentRefs)
return r.validateRouteParentReferences(parentReferences, tr.Namespace)
}

func (r *gatewayAPIReconciler) validateRouteParentReferences(refs []gwapiv1b1.ParentReference, defaultNamespace string) bool {
for _, ref := range refs {
if ref.Kind != nil && *ref.Kind == gatewayapi.KindGateway {
key := types.NamespacedName{
Namespace: gatewayapi.NamespaceDerefOr(ref.Namespace, defaultNamespace),
Name: string(ref.Name),
}

gw := &gwapiv1b1.Gateway{}
if err := r.client.Get(context.Background(), key, gw); err != nil {
r.log.Error(err, "failed to get gateway", "namespace", key.Namespace, "name", key.Name)
return false
}

if !r.validateGatewayForReconcile(gw) {
return false
}
}
}

return true
}
8 changes: 4 additions & 4 deletions internal/status/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,10 @@ func (u *UpdateWriter) Send(update Update) {
//
// Supported objects:
//
// GatewayClasses
// Gateway
// HTTPRoute
// TLSRoute
// GatewayClasses
// Gateway
// HTTPRoute
// TLSRoute
func isStatusEqual(objA, objB interface{}) bool {
opts := cmpopts.IgnoreFields(metav1.Condition{}, "LastTransitionTime", "ObservedGeneration")
switch a := objA.(type) {
Expand Down

0 comments on commit 0711567

Please sign in to comment.