Skip to content

Commit 5f6990f

Browse files
Fawad Khaliqkaranvasnani
Fawad Khaliq
andauthored
Add gateway route controller (#256)
* Add gateway route controller Co-authored-by: Karan Vasnani <vasnk@amazon.com>
1 parent 81b1d48 commit 5f6990f

17 files changed

+1153
-36
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
## AWS App Mesh Controller For K8s
99

10-
AWS App Mesh Controller For K8s is a controller to help manage [App Mesh](https://aws.amazon.com/app-mesh/) resources for a Kubernetes cluster. The controller watches custom resources for changes and reflects those changes into the [App Mesh API](https://docs.aws.amazon.com/app-mesh/latest/APIReference/Welcome.html). It is accompanied by the deployment of three custom resource definitions ([CRDs](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/)): meshes, virtualnodes, and virtualservices. These map to App Mesh API objects which the controller manages for you.
10+
AWS App Mesh Controller For K8s is a controller to help manage [App Mesh](https://aws.amazon.com/app-mesh/) resources for a Kubernetes cluster. The controller watches custom resources for changes and reflects those changes into the [App Mesh API](https://docs.aws.amazon.com/app-mesh/latest/APIReference/Welcome.html). It is accompanied by the deployment of three custom resource definitions ([CRDs](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/)): meshes, virtualnodes, virtualservices, virtualgateways and gatewayroutes. These map to App Mesh API objects which the controller manages for you.
1111

1212
## Documentation
1313
Checkout our [Live Docs](https://aws.github.io/aws-app-mesh-controller-for-k8s/)!

config/crd/kustomization.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ resources:
77
- bases/appmesh.k8s.aws_virtualnodes.yaml
88
- bases/appmesh.k8s.aws_virtualrouters.yaml
99
- bases/appmesh.k8s.aws_virtualgateways.yaml
10-
#- bases/appmesh.k8s.aws_gatewayroutes.yaml
10+
- bases/appmesh.k8s.aws_gatewayroutes.yaml
1111
# +kubebuilder:scaffold:crdkustomizeresource
1212

1313
patchesStrategicMerge:

config/rbac/role.yaml

+20
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,26 @@ rules:
5050
- get
5151
- patch
5252
- update
53+
- apiGroups:
54+
- appmesh.k8s.aws
55+
resources:
56+
- gatewayroutes
57+
verbs:
58+
- create
59+
- delete
60+
- get
61+
- list
62+
- patch
63+
- update
64+
- watch
65+
- apiGroups:
66+
- appmesh.k8s.aws
67+
resources:
68+
- gatewayroutes/status
69+
verbs:
70+
- get
71+
- patch
72+
- update
5373
- apiGroups:
5474
- appmesh.k8s.aws
5575
resources:

config/webhook/manifests.yaml

+36
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,24 @@ metadata:
66
creationTimestamp: null
77
name: mutating-webhook-configuration
88
webhooks:
9+
- clientConfig:
10+
caBundle: Cg==
11+
service:
12+
name: webhook-service
13+
namespace: system
14+
path: /mutate-appmesh-k8s-aws-v1beta2-gatewayroute
15+
failurePolicy: Fail
16+
name: mgatewayroute.appmesh.k8s.aws
17+
rules:
18+
- apiGroups:
19+
- appmesh.k8s.aws
20+
apiVersions:
21+
- v1beta2
22+
operations:
23+
- CREATE
24+
- UPDATE
25+
resources:
26+
- gatewayroutes
927
- clientConfig:
1028
caBundle: Cg==
1129
service:
@@ -121,6 +139,24 @@ metadata:
121139
creationTimestamp: null
122140
name: validating-webhook-configuration
123141
webhooks:
142+
- clientConfig:
143+
caBundle: Cg==
144+
service:
145+
name: webhook-service
146+
namespace: system
147+
path: /validate-appmesh-k8s-aws-v1beta2-gatewayroute
148+
failurePolicy: Fail
149+
name: vgatewayroute.appmesh.k8s.aws
150+
rules:
151+
- apiGroups:
152+
- appmesh.k8s.aws
153+
apiVersions:
154+
- v1beta2
155+
operations:
156+
- CREATE
157+
- UPDATE
158+
resources:
159+
- gatewayroutes
124160
- clientConfig:
125161
caBundle: Cg==
126162
service:

controllers/appmesh/gatewayroute_controller.go

+73-17
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,92 @@ package controllers
1818

1919
import (
2020
"context"
21-
21+
"github.com/aws/aws-app-mesh-controller-for-k8s/pkg/gatewayroute"
22+
"github.com/aws/aws-app-mesh-controller-for-k8s/pkg/k8s"
23+
"github.com/aws/aws-app-mesh-controller-for-k8s/pkg/runtime"
2224
"github.com/go-logr/logr"
23-
"k8s.io/apimachinery/pkg/runtime"
2425
ctrl "sigs.k8s.io/controller-runtime"
2526
"sigs.k8s.io/controller-runtime/pkg/client"
27+
"sigs.k8s.io/controller-runtime/pkg/controller"
28+
"sigs.k8s.io/controller-runtime/pkg/handler"
29+
"sigs.k8s.io/controller-runtime/pkg/source"
2630

27-
appmeshv1beta2 "github.com/aws/aws-app-mesh-controller-for-k8s/apis/appmesh/v1beta2"
31+
appmesh "github.com/aws/aws-app-mesh-controller-for-k8s/apis/appmesh/v1beta2"
2832
)
2933

30-
// GatewayRouteReconciler reconciles a GatewayRoute object
31-
type GatewayRouteReconciler struct {
32-
client.Client
33-
Log logr.Logger
34-
Scheme *runtime.Scheme
34+
// NewGatewayRouteReconciler constructs new gatewayRouteReconciler
35+
func NewGatewayRouteReconciler(
36+
k8sClient client.Client,
37+
finalizerManager k8s.FinalizerManager,
38+
grResManager gatewayroute.ResourceManager,
39+
log logr.Logger) *gatewayRouteReconciler {
40+
return &gatewayRouteReconciler{
41+
k8sClient: k8sClient,
42+
finalizerManager: finalizerManager,
43+
grResManager: grResManager,
44+
enqueueRequestsForMeshEvents: gatewayroute.NewEnqueueRequestsForMeshEvents(k8sClient, log),
45+
enqueueRequestsForVirtualGatewayEvents: gatewayroute.NewEnqueueRequestsForVirtualGatewayEvents(k8sClient, log),
46+
log: log,
47+
}
3548
}
3649

37-
//// +kubebuilder:rbac:groups=appmesh.k8s.aws,resources=gatewayroutes,verbs=get;list;watch;create;update;patch;delete
38-
//// +kubebuilder:rbac:groups=appmesh.k8s.aws,resources=gatewayroutes/status,verbs=get;update;patch
50+
// gatewayRouteReconciler reconciles a GatewayRoute object
51+
type gatewayRouteReconciler struct {
52+
k8sClient client.Client
53+
finalizerManager k8s.FinalizerManager
54+
grResManager gatewayroute.ResourceManager
3955

40-
func (r *GatewayRouteReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
41-
_ = context.Background()
42-
_ = r.Log.WithValues("gatewayroute", req.NamespacedName)
56+
enqueueRequestsForMeshEvents handler.EventHandler
57+
enqueueRequestsForVirtualGatewayEvents handler.EventHandler
58+
log logr.Logger
59+
}
4360

44-
// your logic here
61+
// +kubebuilder:rbac:groups=appmesh.k8s.aws,resources=gatewayroutes,verbs=get;list;watch;create;update;patch;delete
62+
// +kubebuilder:rbac:groups=appmesh.k8s.aws,resources=gatewayroutes/status,verbs=get;update;patch
4563

46-
return ctrl.Result{}, nil
64+
func (r *gatewayRouteReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
65+
return runtime.HandleReconcileError(r.reconcile(req), r.log)
4766
}
4867

49-
func (r *GatewayRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
68+
func (r *gatewayRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
5069
return ctrl.NewControllerManagedBy(mgr).
51-
For(&appmeshv1beta2.GatewayRoute{}).
70+
For(&appmesh.GatewayRoute{}).
71+
Watches(&source.Kind{Type: &appmesh.Mesh{}}, r.enqueueRequestsForMeshEvents).
72+
Watches(&source.Kind{Type: &appmesh.VirtualGateway{}}, r.enqueueRequestsForVirtualGatewayEvents).
73+
WithOptions(controller.Options{MaxConcurrentReconciles: 3}).
5274
Complete(r)
5375
}
76+
77+
func (r *gatewayRouteReconciler) reconcile(req ctrl.Request) error {
78+
ctx := context.Background()
79+
gr := &appmesh.GatewayRoute{}
80+
if err := r.k8sClient.Get(ctx, req.NamespacedName, gr); err != nil {
81+
return client.IgnoreNotFound(err)
82+
}
83+
if !gr.DeletionTimestamp.IsZero() {
84+
return r.cleanupGatewayRoute(ctx, gr)
85+
}
86+
return r.reconcileGatewayRoute(ctx, gr)
87+
}
88+
89+
func (r *gatewayRouteReconciler) reconcileGatewayRoute(ctx context.Context, gr *appmesh.GatewayRoute) error {
90+
if err := r.finalizerManager.AddFinalizers(ctx, gr, k8s.FinalizerAWSAppMeshResources); err != nil {
91+
return err
92+
}
93+
if err := r.grResManager.Reconcile(ctx, gr); err != nil {
94+
return err
95+
}
96+
return nil
97+
}
98+
99+
func (r *gatewayRouteReconciler) cleanupGatewayRoute(ctx context.Context, gr *appmesh.GatewayRoute) error {
100+
if k8s.HasFinalizer(gr, k8s.FinalizerAWSAppMeshResources) {
101+
if err := r.grResManager.Cleanup(ctx, gr); err != nil {
102+
return err
103+
}
104+
if err := r.finalizerManager.RemoveFinalizers(ctx, gr, k8s.FinalizerAWSAppMeshResources); err != nil {
105+
return err
106+
}
107+
}
108+
return nil
109+
}

main.go

+10-5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
ctrl "sigs.k8s.io/controller-runtime"
3939
"sigs.k8s.io/controller-runtime/pkg/log/zap"
4040

41+
"github.com/aws/aws-app-mesh-controller-for-k8s/pkg/gatewayroute"
4142
"github.com/aws/aws-app-mesh-controller-for-k8s/pkg/inject"
4243
"github.com/aws/aws-app-mesh-controller-for-k8s/pkg/mesh"
4344
"github.com/aws/aws-app-mesh-controller-for-k8s/pkg/virtualgateway"
@@ -127,12 +128,14 @@ func main() {
127128
cloudMapInstancesReconciler := cloudmap.NewDefaultInstancesReconciler(mgr.GetClient(), cloud.CloudMap(), ctrl.Log, stopChan)
128129
meshResManager := mesh.NewDefaultResourceManager(mgr.GetClient(), cloud.AppMesh(), cloud.AccountID(), ctrl.Log)
129130
vgResManager := virtualgateway.NewDefaultResourceManager(mgr.GetClient(), cloud.AppMesh(), referencesResolver, cloud.AccountID(), ctrl.Log)
131+
grResManager := gatewayroute.NewDefaultResourceManager(mgr.GetClient(), cloud.AppMesh(), referencesResolver, cloud.AccountID(), ctrl.Log)
130132
vnResManager := virtualnode.NewDefaultResourceManager(mgr.GetClient(), cloud.AppMesh(), referencesResolver, cloud.AccountID(), ctrl.Log)
131133
vsResManager := virtualservice.NewDefaultResourceManager(mgr.GetClient(), cloud.AppMesh(), referencesResolver, cloud.AccountID(), ctrl.Log)
132134
vrResManager := virtualrouter.NewDefaultResourceManager(mgr.GetClient(), cloud.AppMesh(), referencesResolver, cloud.AccountID(), ctrl.Log)
133135
cloudMapResManager := cloudmap.NewDefaultResourceManager(mgr.GetClient(), cloud.CloudMap(), referencesResolver, virtualNodeEndpointResolver, cloudMapInstancesReconciler, enableCustomHealthCheck, ctrl.Log)
134136
msReconciler := appmeshcontroller.NewMeshReconciler(mgr.GetClient(), finalizerManager, meshMembersFinalizer, meshResManager, ctrl.Log.WithName("controllers").WithName("Mesh"))
135137
vgReconciler := appmeshcontroller.NewVirtualGatewayReconciler(mgr.GetClient(), finalizerManager, vgMembersFinalizer, vgResManager, ctrl.Log.WithName("controllers").WithName("VirtualGateway"))
138+
grReconciler := appmeshcontroller.NewGatewayRouteReconciler(mgr.GetClient(), finalizerManager, grResManager, ctrl.Log.WithName("controllers").WithName("GatewayRoute"))
136139
vnReconciler := appmeshcontroller.NewVirtualNodeReconciler(mgr.GetClient(), finalizerManager, vnResManager, ctrl.Log.WithName("controllers").WithName("VirtualNode"))
137140
cloudMapReconciler := appmeshcontroller.NewCloudMapReconciler(mgr.GetClient(), finalizerManager, cloudMapResManager, ctrl.Log.WithName("controllers").WithName("CloudMap"))
138141
vsReconciler := appmeshcontroller.NewVirtualServiceReconciler(mgr.GetClient(), finalizerManager, referencesIndexer, vsResManager, ctrl.Log.WithName("controllers").WithName("VirtualService"))
@@ -145,12 +148,14 @@ func main() {
145148
setupLog.Error(err, "unable to create controller", "controller", "VirtualService")
146149
os.Exit(1)
147150
}
148-
149151
if err = vgReconciler.SetupWithManager(mgr); err != nil {
150152
setupLog.Error(err, "unable to create controller", "controller", "VirtualGateway")
151153
os.Exit(1)
152154
}
153-
155+
if err = grReconciler.SetupWithManager(mgr); err != nil {
156+
setupLog.Error(err, "unable to create controller", "controller", "GatewayRoute")
157+
os.Exit(1)
158+
}
154159
if err = vnReconciler.SetupWithManager(mgr); err != nil {
155160
setupLog.Error(err, "unable to create controller", "controller", "VirtualNode")
156161
os.Exit(1)
@@ -165,15 +170,15 @@ func main() {
165170
}
166171

167172
meshMembershipDesignator := mesh.NewMembershipDesignator(mgr.GetClient())
168-
//vgMembershipDesignator := virtualgateway.NewMembershipDesignator(mgr.GetClient())
173+
vgMembershipDesignator := virtualgateway.NewMembershipDesignator(mgr.GetClient())
169174
vnMembershipDesignator := virtualnode.NewMembershipDesignator(mgr.GetClient())
170175
sidecarInjector := inject.NewSidecarInjector(injectConfig, cloud.Region(), mgr.GetClient(), referencesResolver, vnMembershipDesignator)
171176
appmeshwebhook.NewMeshMutator().SetupWithManager(mgr)
172177
appmeshwebhook.NewMeshValidator().SetupWithManager(mgr)
173178
appmeshwebhook.NewVirtualGatewayMutator(meshMembershipDesignator).SetupWithManager(mgr)
174179
appmeshwebhook.NewVirtualGatewayValidator().SetupWithManager(mgr)
175-
//appmeshwebhook.NewGatewayRouteMutator(meshMembershipDesignator, vgMembershipDesignator).SetupWithManager(mgr)
176-
//appmeshwebhook.NewGatewayRouteValidator().SetupWithManager(mgr)
180+
appmeshwebhook.NewGatewayRouteMutator(meshMembershipDesignator, vgMembershipDesignator).SetupWithManager(mgr)
181+
appmeshwebhook.NewGatewayRouteValidator().SetupWithManager(mgr)
177182
appmeshwebhook.NewVirtualNodeMutator(meshMembershipDesignator).SetupWithManager(mgr)
178183
appmeshwebhook.NewVirtualNodeValidator().SetupWithManager(mgr)
179184
appmeshwebhook.NewVirtualServiceMutator(meshMembershipDesignator).SetupWithManager(mgr)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package gatewayroute
2+
3+
import (
4+
"context"
5+
appmesh "github.com/aws/aws-app-mesh-controller-for-k8s/apis/appmesh/v1beta2"
6+
"github.com/aws/aws-app-mesh-controller-for-k8s/pkg/k8s"
7+
"github.com/aws/aws-app-mesh-controller-for-k8s/pkg/mesh"
8+
"github.com/go-logr/logr"
9+
"k8s.io/client-go/util/workqueue"
10+
ctrl "sigs.k8s.io/controller-runtime"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
"sigs.k8s.io/controller-runtime/pkg/event"
13+
"sigs.k8s.io/controller-runtime/pkg/handler"
14+
)
15+
16+
func NewEnqueueRequestsForMeshEvents(k8sClient client.Client, log logr.Logger) *enqueueRequestsForMeshEvents {
17+
return &enqueueRequestsForMeshEvents{
18+
k8sClient: k8sClient,
19+
log: log,
20+
}
21+
}
22+
23+
var _ handler.EventHandler = (*enqueueRequestsForMeshEvents)(nil)
24+
25+
type enqueueRequestsForMeshEvents struct {
26+
k8sClient client.Client
27+
log logr.Logger
28+
}
29+
30+
// Create is called in response to an create event
31+
func (h *enqueueRequestsForMeshEvents) Create(e event.CreateEvent, queue workqueue.RateLimitingInterface) {
32+
// no-op
33+
}
34+
35+
// Update is called in response to an update event
36+
func (h *enqueueRequestsForMeshEvents) Update(e event.UpdateEvent, queue workqueue.RateLimitingInterface) {
37+
// gatewayRoute reconcile depends on mesh is active or not.
38+
// so we only need to trigger gatewayRoute reconcile if mesh's active status changed.
39+
msOld := e.ObjectOld.(*appmesh.Mesh)
40+
msNew := e.ObjectNew.(*appmesh.Mesh)
41+
42+
if mesh.IsMeshActive(msOld) != mesh.IsMeshActive(msNew) {
43+
h.enqueueGatewayRoutesForMesh(context.Background(), queue, msNew)
44+
}
45+
}
46+
47+
// Delete is called in response to a delete event
48+
func (h *enqueueRequestsForMeshEvents) Delete(e event.DeleteEvent, queue workqueue.RateLimitingInterface) {
49+
// no-op
50+
}
51+
52+
// Generic is called in response to an event of an unknown type or a synthetic event triggered as a cron or
53+
// external trigger request
54+
func (h *enqueueRequestsForMeshEvents) Generic(e event.GenericEvent, queue workqueue.RateLimitingInterface) {
55+
// no-op
56+
}
57+
58+
func (h *enqueueRequestsForMeshEvents) enqueueGatewayRoutesForMesh(ctx context.Context, queue workqueue.RateLimitingInterface, ms *appmesh.Mesh) {
59+
grList := &appmesh.GatewayRouteList{}
60+
if err := h.k8sClient.List(ctx, grList); err != nil {
61+
h.log.Error(err, "failed to enqueue gatewayRoutes for mesh events",
62+
"mesh", k8s.NamespacedName(ms))
63+
return
64+
}
65+
for _, gr := range grList.Items {
66+
if gr.Spec.MeshRef == nil || !mesh.IsMeshReferenced(ms, *gr.Spec.MeshRef) {
67+
continue
68+
}
69+
queue.Add(ctrl.Request{NamespacedName: k8s.NamespacedName(&gr)})
70+
}
71+
}

0 commit comments

Comments
 (0)