Skip to content

Commit

Permalink
feat(gateway): reconcile Gateways if MeshGatewayConfig changes
Browse files Browse the repository at this point in the history
Signed-off-by: Mike Beaumont <mjboamail@gmail.com>
  • Loading branch information
michaelbeaumont committed Apr 11, 2022
1 parent 463c696 commit a08225b
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ type GatewayClassReconciler struct {
Log logr.Logger
}

const gatewayClassKey = ".metadata.gatewayClass"
// gatewayClassField is needed for both GatewayClassReconciler and
// GatewayReconciler.
const gatewayClassField = ".metadata.gatewayClass"

// parametersRefField is important for both GatewayReconciler and
// GatewayClassReconciler.
const parametersRefField = ".metadata.parametersRef"

// Reconcile handles maintaining the GatewayClass finalizer.
func (r *GatewayClassReconciler) Reconcile(ctx context.Context, req kube_ctrl.Request) (kube_ctrl.Result, error) {
Expand All @@ -47,7 +53,7 @@ func (r *GatewayClassReconciler) Reconcile(ctx context.Context, req kube_ctrl.Re

gateways := &gatewayapi.GatewayList{}
if err := r.Client.List(
ctx, gateways, kube_client.MatchingFields{gatewayClassKey: class.Name},
ctx, gateways, kube_client.MatchingFields{gatewayClassField: class.Name},
); err != nil {
return kube_ctrl.Result{}, err
}
Expand Down Expand Up @@ -172,6 +178,38 @@ func gatewayToClassMapper(l logr.Logger, client kube_client.Client) kube_handler
}
}

// gatewayClassesForConfig returns a function that calculates which
// GatewayClasses might be affected by changes in a MeshGatewayConfig.
func gatewayClassesForConfig(l logr.Logger, client kube_client.Client) kube_handler.MapFunc {
l = l.WithName("gatewaysForConfig")

return func(obj kube_client.Object) []kube_reconcile.Request {
config, ok := obj.(*mesh_k8s.MeshGatewayConfig)
if !ok {
l.Error(nil, "unexpected error converting to be mapped %T object to MeshGatewayConfig", obj)
return nil
}

classes := &gatewayapi.GatewayClassList{}
if err := client.List(
context.Background(), classes, kube_client.MatchingFields{parametersRefField: config.Name},
); err != nil {
l.Error(err, "unexpected error listing GatewayClasses")
return nil
}

var requests []kube_reconcile.Request

for _, class := range classes.Items {
requests = append(requests, kube_reconcile.Request{
NamespacedName: kube_client.ObjectKeyFromObject(&class),
})
}

return requests
}
}

func (r *GatewayClassReconciler) SetupWithManager(mgr kube_ctrl.Manager) error {
// Add an index to Gateways for use in Reconcile
indexLog := r.Log.WithName("gatewayClassNameIndexer")
Expand All @@ -188,15 +226,36 @@ func (r *GatewayClassReconciler) SetupWithManager(mgr kube_ctrl.Manager) error {

// this index is also needed by GatewayReconciler!
if err := mgr.GetFieldIndexer().IndexField(
context.Background(), &gatewayapi.Gateway{}, gatewayClassKey, gatewayClassNameIndexer,
context.Background(), &gatewayapi.Gateway{}, gatewayClassField, gatewayClassNameIndexer,
); err != nil {
return err
}

if err := mgr.GetFieldIndexer().IndexField(context.Background(), &gatewayapi.GatewayClass{}, parametersRefField, func(obj kube_client.Object) []string {
class := obj.(*gatewayapi.GatewayClass)

ref := class.Spec.ParametersRef

if class.Spec.ControllerName != common.ControllerName || ref == nil || ref.Kind != "MeshGatewayConfig" || ref.Group != gatewayapi.Group(mesh_k8s.GroupVersion.Group) {
return nil
}

return []string{ref.Name}
}); err != nil {
return err
}

return kube_ctrl.NewControllerManagedBy(mgr).
For(&gatewayapi.GatewayClass{}).
// When something changes with Gateways, we want to reconcile
// GatewayClasses
Watches(&kube_source.Kind{Type: &gatewayapi.Gateway{}}, kube_handler.EnqueueRequestsFromMapFunc(gatewayToClassMapper(r.Log, r.Client))).
Watches(&kube_source.Kind{
Type: &gatewayapi.Gateway{}},
kube_handler.EnqueueRequestsFromMapFunc(gatewayToClassMapper(r.Log, r.Client)),
).
Watches(
&kube_source.Kind{Type: &mesh_k8s.MeshGatewayConfig{}},
kube_handler.EnqueueRequestsFromMapFunc(gatewayClassesForConfig(r.Log, r.Client)),
).
Complete(r)
}
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func gatewaysForClass(l logr.Logger, client kube_client.Client) kube_handler.Map

gateways := &gatewayapi.GatewayList{}
if err := client.List(
context.Background(), gateways, kube_client.MatchingFields{gatewayClassKey: class.Name},
context.Background(), gateways, kube_client.MatchingFields{gatewayClassField: class.Name},
); err != nil {
l.Error(err, "unexpected error listing Gateways")
return nil
Expand All @@ -201,6 +201,47 @@ func gatewaysForClass(l logr.Logger, client kube_client.Client) kube_handler.Map
}
}

// gatewaysForConfig returns a function that calculates which Gateways might
// be affected by changes in a MeshGatewayConfig.
func gatewaysForConfig(l logr.Logger, client kube_client.Client) kube_handler.MapFunc {
l = l.WithName("gatewaysForConfig")

return func(obj kube_client.Object) []kube_reconcile.Request {
config, ok := obj.(*mesh_k8s.MeshGatewayConfig)
if !ok {
l.Error(nil, "unexpected error converting to be mapped %T object to MeshGatewayConfig", obj)
return nil
}

classes := &gatewayapi.GatewayClassList{}
if err := client.List(
context.Background(), classes, kube_client.MatchingFields{parametersRefField: config.Name},
); err != nil {
l.Error(err, "unexpected error listing GatewayClasses")
return nil
}

var requests []kube_reconcile.Request

for _, class := range classes.Items {
gateways := &gatewayapi.GatewayList{}
if err := client.List(
context.Background(), gateways, kube_client.MatchingFields{gatewayClassField: class.Name},
); err != nil {
l.Error(err, "unexpected error listing Gateways")
return nil
}
for _, gateway := range gateways.Items {
requests = append(requests, kube_reconcile.Request{
NamespacedName: kube_client.ObjectKeyFromObject(&gateway),
})
}
}

return requests
}
}

func (r *GatewayReconciler) SetupWithManager(mgr kube_ctrl.Manager) error {
// This index helps us list routes that point to a MeshGateway in
// attachedListenersForMeshGateway.
Expand Down Expand Up @@ -238,5 +279,9 @@ func (r *GatewayReconciler) SetupWithManager(mgr kube_ctrl.Manager) error {
&kube_source.Kind{Type: &gatewayapi.GatewayClass{}},
kube_handler.EnqueueRequestsFromMapFunc(gatewaysForClass(r.Log, r.Client)),
).
Watches(
&kube_source.Kind{Type: &mesh_k8s.MeshGatewayConfig{}},
kube_handler.EnqueueRequestsFromMapFunc(gatewaysForConfig(r.Log, r.Client)),
).
Complete(r)
}
11 changes: 11 additions & 0 deletions test/e2e/gateway/gatewayapi/gateway_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,17 @@ spec:

It("should create the right number of pods", func() {
Expect(cluster.WaitApp("kuma", "kuma-test", 3)).To(Succeed())

newHaConfig := `
apiVersion: kuma.io/v1alpha1
kind: MeshGatewayConfig
metadata:
name: ha-config
spec:
replicas: 4`
Expect(YamlK8s(newHaConfig)(cluster)).To(Succeed())

Expect(cluster.WaitApp("kuma", "kuma-test", 4)).To(Succeed())
})
})

Expand Down

0 comments on commit a08225b

Please sign in to comment.