@@ -3,9 +3,11 @@ package controller
33import (
44 "context"
55 "fmt"
6+ "reflect"
67
78 "github.com/go-logr/logr"
89 dashv1alpha1 "github.com/pluralsh/dash-controller/apis/dash/v1alpha1"
10+ "github.com/pluralsh/dash-controller/pkg/kubernetes"
911 appsv1 "k8s.io/api/apps/v1"
1012 corev1 "k8s.io/api/core/v1"
1113 networkingv1 "k8s.io/api/networking/v1"
@@ -14,6 +16,13 @@ import (
1416 "k8s.io/apimachinery/pkg/util/intstr"
1517 ctrl "sigs.k8s.io/controller-runtime"
1618 "sigs.k8s.io/controller-runtime/pkg/client"
19+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
20+ )
21+
22+ const (
23+ IngressFinalizer = "pluralsh.dash-controller/ingress-protection"
24+ DeploymentFinalizer = "pluralsh.dash-controller/deployment-protection"
25+ ServiceFinalizer = "pluralsh.dash-controller/service-protection"
1726)
1827
1928// Reconciler reconciles a DatabaseRequest object
@@ -36,43 +45,47 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
3645 name := dashApp .Name
3746 namespace := dashApp .Namespace
3847
39- deployment := & appsv1.Deployment {}
40- if err := r .Get (ctx , client.ObjectKey {Namespace : namespace , Name : name }, deployment ); err != nil {
41- if ! apierrors .IsNotFound (err ) {
42- return ctrl.Result {}, err
48+ if ! dashApp .GetDeletionTimestamp ().IsZero () {
49+ if controllerutil .ContainsFinalizer (dashApp , IngressFinalizer ) {
50+ log .Info ("delete ingress" )
51+ if err := r .Delete (ctx , & networkingv1.Ingress {ObjectMeta : metav1.ObjectMeta {Name : name , Namespace : namespace }}); err != nil {
52+ if ! apierrors .IsNotFound (err ) {
53+ return ctrl.Result {}, err
54+ }
55+ }
56+ kubernetes .TryRemoveFinalizer (ctx , r .Client , dashApp , IngressFinalizer )
4357 }
44- log .Info ("create deployment" )
45- deployment = genDeployment (dashApp )
46- if err := r .Create (ctx , deployment ); err != nil {
47- return ctrl.Result {}, err
58+ if controllerutil .ContainsFinalizer (dashApp , ServiceFinalizer ) {
59+ log .Info ("delete service" )
60+ if err := r .Delete (ctx , & corev1.Service {ObjectMeta : metav1.ObjectMeta {Name : name , Namespace : namespace }}); err != nil {
61+ if ! apierrors .IsNotFound (err ) {
62+ return ctrl.Result {}, err
63+ }
64+ }
65+ kubernetes .TryRemoveFinalizer (ctx , r .Client , dashApp , ServiceFinalizer )
4866 }
67+ if controllerutil .ContainsFinalizer (dashApp , DeploymentFinalizer ) {
68+ log .Info ("delete deployment" )
69+ if err := r .Delete (ctx , & appsv1.Deployment {ObjectMeta : metav1.ObjectMeta {Name : name , Namespace : namespace }}); err != nil {
70+ if ! apierrors .IsNotFound (err ) {
71+ return ctrl.Result {}, err
72+ }
73+ }
74+ kubernetes .TryRemoveFinalizer (ctx , r .Client , dashApp , DeploymentFinalizer )
75+ }
76+ return ctrl.Result {}, nil
4977 }
5078
51- svc := & corev1.Service {}
52- if err := r .Get (ctx , client.ObjectKey {Namespace : namespace , Name : name }, svc ); err != nil {
53- if ! apierrors .IsNotFound (err ) {
54- return ctrl.Result {}, err
55- }
56- log .Info ("create service" )
57- svc = generateService (dashApp )
58- if err := r .Create (ctx , svc ); err != nil {
59- return ctrl.Result {}, err
60- }
79+ if err := r .createUpdateDeployment (ctx , log , dashApp ); err != nil {
80+ return ctrl.Result {}, err
6181 }
6282
63- if dashApp .Spec .Ingress != nil {
64- ingress := & networkingv1.Ingress {}
65- if err := r .Get (ctx , client.ObjectKey {Namespace : namespace , Name : name }, ingress ); err != nil {
66- if ! apierrors .IsNotFound (err ) {
67- return ctrl.Result {}, err
68- }
83+ if err := r .createUpdateService (ctx , log , dashApp ); err != nil {
84+ return ctrl.Result {}, err
85+ }
6986
70- log .Info ("create ingress" )
71- ingress = genIngress (dashApp )
72- if err := r .Create (ctx , ingress ); err != nil {
73- return ctrl.Result {}, err
74- }
75- }
87+ if err := r .createUpdateIngress (ctx , log , dashApp ); err != nil {
88+ return ctrl.Result {}, err
7689 }
7790
7891 dashApp .Status .Ready = true
@@ -217,6 +230,127 @@ func baseAppLabels(name string, additionalLabels map[string]string) map[string]s
217230 return labels
218231}
219232
233+ func (r * Reconciler ) createUpdateIngress (ctx context.Context , log logr.Logger , dashApp * dashv1alpha1.DashApplication ) error {
234+ if dashApp .Spec .Ingress != nil {
235+ update := false
236+ name := dashApp .Name
237+ namespace := dashApp .Namespace
238+ newIngress := genIngress (dashApp )
239+ ingress := & networkingv1.Ingress {}
240+ if err := r .Get (ctx , client.ObjectKey {Namespace : namespace , Name : name }, ingress ); err != nil {
241+ if ! apierrors .IsNotFound (err ) {
242+ return err
243+ }
244+
245+ log .Info ("create ingress" )
246+ if err := r .Create (ctx , newIngress ); err != nil {
247+ return err
248+ }
249+ if err := kubernetes .TryAddFinalizer (ctx , r .Client , dashApp , IngressFinalizer ); err != nil {
250+ return err
251+ }
252+ return nil
253+ }
254+ if ! reflect .DeepEqual (ingress .Annotations , newIngress .Annotations ) {
255+ update = true
256+ ingress .Annotations = newIngress .Annotations
257+ }
258+ if ! reflect .DeepEqual (ingress .Spec .IngressClassName , newIngress .Spec .IngressClassName ) {
259+ update = true
260+ ingress .Spec .IngressClassName = newIngress .Spec .IngressClassName
261+ }
262+ if ! reflect .DeepEqual (ingress .Spec .Rules [0 ].Host , newIngress .Spec .Rules [0 ].Host ) {
263+ update = true
264+ ingress .Spec .Rules [0 ].Host = newIngress .Spec .Rules [0 ].Host
265+ }
266+ if ! reflect .DeepEqual (ingress .Spec .Rules [0 ].HTTP .Paths , newIngress .Spec .Rules [0 ].HTTP .Paths ) {
267+ update = true
268+ ingress .Spec .Rules [0 ].HTTP .Paths = newIngress .Spec .Rules [0 ].HTTP .Paths
269+ }
270+
271+ if update {
272+ log .Info ("update ingress" )
273+ return r .Update (ctx , ingress )
274+ }
275+ }
276+ return nil
277+ }
278+
279+ func (r * Reconciler ) createUpdateService (ctx context.Context , log logr.Logger , dashApp * dashv1alpha1.DashApplication ) error {
280+ name := dashApp .Name
281+ namespace := dashApp .Namespace
282+ newService := generateService (dashApp )
283+ svc := & corev1.Service {}
284+ if err := r .Get (ctx , client.ObjectKey {Namespace : namespace , Name : name }, svc ); err != nil {
285+ if ! apierrors .IsNotFound (err ) {
286+ return err
287+ }
288+ log .Info ("create service" )
289+ if err := r .Create (ctx , newService ); err != nil {
290+ return err
291+ }
292+ if err := kubernetes .TryAddFinalizer (ctx , r .Client , dashApp , ServiceFinalizer ); err != nil {
293+ return err
294+ }
295+ return nil
296+ }
297+
298+ if ! reflect .DeepEqual (newService .Annotations , svc .Annotations ) {
299+ svc .Annotations = newService .Annotations
300+ log .Info ("update service" )
301+ return r .Update (ctx , svc )
302+ }
303+
304+ return nil
305+ }
306+
307+ func (r * Reconciler ) createUpdateDeployment (ctx context.Context , log logr.Logger , dashApp * dashv1alpha1.DashApplication ) error {
308+ var update bool
309+ name := dashApp .Name
310+ namespace := dashApp .Namespace
311+ newDeployment := genDeployment (dashApp )
312+ deployment := & appsv1.Deployment {}
313+ if err := r .Get (ctx , client.ObjectKey {Namespace : namespace , Name : name }, deployment ); err != nil {
314+ if ! apierrors .IsNotFound (err ) {
315+ return err
316+ }
317+ log .Info ("create deployment" )
318+ if err := r .Create (ctx , newDeployment ); err != nil {
319+ return err
320+ }
321+ if err := kubernetes .TryAddFinalizer (ctx , r .Client , dashApp , DeploymentFinalizer ); err != nil {
322+ return err
323+ }
324+ return nil
325+ }
326+
327+ if ! reflect .DeepEqual (newDeployment .Spec .Replicas , deployment .Spec .Replicas ) {
328+ deployment .Spec .Replicas = newDeployment .Spec .Replicas
329+ update = true
330+ }
331+ if ! reflect .DeepEqual (newDeployment .Spec .Template .Spec .Containers [0 ].Ports , deployment .Spec .Template .Spec .Containers [0 ].Ports ) {
332+ deployment .Spec .Template .Spec .Containers [0 ].Ports = newDeployment .Spec .Template .Spec .Containers [0 ].Ports
333+ update = true
334+ }
335+ if ! reflect .DeepEqual (newDeployment .Spec .Template .Spec .Containers [0 ].Image , deployment .Spec .Template .Spec .Containers [0 ].Image ) {
336+ deployment .Spec .Template .Spec .Containers [0 ].Image = newDeployment .Spec .Template .Spec .Containers [0 ].Image
337+ update = true
338+ }
339+ if ! reflect .DeepEqual (newDeployment .Spec .Template .Spec .Containers [0 ].Command , deployment .Spec .Template .Spec .Containers [0 ].Command ) {
340+ deployment .Spec .Template .Spec .Containers [0 ].Command = newDeployment .Spec .Template .Spec .Containers [0 ].Command
341+ update = true
342+ }
343+ if ! reflect .DeepEqual (newDeployment .Spec .Template .Spec .Containers [0 ].Args , deployment .Spec .Template .Spec .Containers [0 ].Args ) {
344+ deployment .Spec .Template .Spec .Containers [0 ].Args = newDeployment .Spec .Template .Spec .Containers [0 ].Args
345+ update = true
346+ }
347+ if update {
348+ log .Info ("update deployment" )
349+ return r .Update (ctx , deployment )
350+ }
351+ return nil
352+ }
353+
220354// SetupWithManager sets up the controller with the Manager.
221355func (r * Reconciler ) SetupWithManager (mgr ctrl.Manager ) error {
222356 return ctrl .NewControllerManagedBy (mgr ).
0 commit comments