Skip to content

Commit 061430a

Browse files
committed
Share controller code further
1 parent 6aef030 commit 061430a

File tree

3 files changed

+400
-245
lines changed

3 files changed

+400
-245
lines changed

common/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ type BaseComponentService interface {
126126
type BaseComponentNetworkPolicy interface {
127127
GetNamespaceLabels() map[string]string
128128
GetFromLabels() map[string]string
129+
IsDisabled() bool
129130
}
130131

131132
// BaseComponentMonitoring represents basic service monitoring configuration

controllers/runtimecomponent_controller.go

Lines changed: 24 additions & 245 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ import (
2020
"context"
2121
"fmt"
2222
"os"
23-
"strings"
2423

2524
"github.com/application-stacks/runtime-component-operator/common"
26-
"github.com/pkg/errors"
2725

2826
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2927
"sigs.k8s.io/controller-runtime/pkg/event"
@@ -50,7 +48,6 @@ import (
5048
networkingv1 "k8s.io/api/networking/v1"
5149
kerrors "k8s.io/apimachinery/pkg/api/errors"
5250
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
53-
"k8s.io/apimachinery/pkg/types"
5451
servingv1 "knative.dev/serving/pkg/apis/serving/v1"
5552
"sigs.k8s.io/controller-runtime/pkg/client"
5653
)
@@ -118,7 +115,7 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
118115

119116
// Fetch the RuntimeComponent instance
120117
instance := &appstacksv1beta2.RuntimeComponent{}
121-
var ba common.BaseComponent = instance
118+
// var ba common.BaseComponent = instance
122119
err = r.GetClient().Get(context.TODO(), req.NamespacedName, instance)
123120
if err != nil {
124121
if kerrors.IsNotFound(err) {
@@ -163,64 +160,13 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
163160
Namespace: instance.Namespace,
164161
}
165162

166-
imageReferenceOld := instance.Status.ImageReference
167-
instance.Status.ImageReference = instance.Spec.ApplicationImage
168-
if r.IsOpenShift() {
169-
image, err := imageutil.ParseDockerImageReference(instance.Spec.ApplicationImage)
170-
if err == nil {
171-
isTag := &imagev1.ImageStreamTag{}
172-
isTagName := imageutil.JoinImageStreamTag(image.Name, image.Tag)
173-
isTagNamespace := image.Namespace
174-
if isTagNamespace == "" {
175-
isTagNamespace = instance.Namespace
176-
}
177-
key := types.NamespacedName{Name: isTagName, Namespace: isTagNamespace}
178-
err = r.GetAPIReader().Get(context.Background(), key, isTag)
179-
// Call ManageError only if the error type is not found or is not forbidden. Forbidden could happen
180-
// when the operator tries to call GET for ImageStreamTags on a namespace that doesn't exists (e.g.
181-
// cannot get imagestreamtags.image.openshift.io in the namespace "navidsh": no RBAC policy matched)
182-
if err == nil {
183-
image := isTag.Image
184-
if image.DockerImageReference != "" {
185-
instance.Status.ImageReference = image.DockerImageReference
186-
}
187-
} else if err != nil && !kerrors.IsNotFound(err) && !kerrors.IsForbidden(err) && !strings.Contains(isTagName, "/") {
188-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
189-
}
190-
}
191-
}
192-
if imageReferenceOld != instance.Status.ImageReference {
193-
reqLogger.Info("Updating status.imageReference", "status.imageReference", instance.Status.ImageReference)
194-
err = r.UpdateStatus(instance)
195-
if err != nil {
196-
reqLogger.Error(err, "Error updating RuntimeComponent status")
197-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
198-
}
199-
}
200-
201-
if instance.Spec.ServiceAccountName == nil || *instance.Spec.ServiceAccountName == "" {
202-
serviceAccount := &corev1.ServiceAccount{ObjectMeta: defaultMeta}
203-
err = r.CreateOrUpdate(serviceAccount, instance, func() error {
204-
return appstacksutils.CustomizeServiceAccount(serviceAccount, instance, r.GetClient())
205-
})
206-
if err != nil {
207-
reqLogger.Error(err, "Failed to reconcile ServiceAccount")
208-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
209-
}
210-
} else {
211-
serviceAccount := &corev1.ServiceAccount{ObjectMeta: defaultMeta}
212-
err = r.DeleteResource(serviceAccount)
213-
if err != nil {
214-
reqLogger.Error(err, "Failed to delete ServiceAccount")
215-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
216-
}
163+
if err = r.UpdateImageReference(instance); err != nil {
164+
reqLogger.Error(err, "Error updating RuntimeComponent")
165+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
217166
}
218167

219-
// Check if the ServiceAccount has a valid pull secret before creating the deployment/statefulset
220-
// or setting up knative. Otherwise the pods can go into an ImagePullBackOff loop
221-
saErr := appstacksutils.ServiceAccountPullSecretExists(instance, r.GetClient())
222-
if saErr != nil {
223-
return r.ManageError(saErr, common.StatusConditionTypeReconciled, instance)
168+
if err = r.UpdateServiceAccount(instance, defaultMeta); err != nil {
169+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
224170
}
225171

226172
isKnativeSupported, err := r.IsGroupVersionSupported(servingv1.SchemeGroupVersion.String(), "Service")
@@ -231,47 +177,12 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
231177
}
232178

233179
if instance.Spec.CreateKnativeService != nil && *instance.Spec.CreateKnativeService {
234-
// Clean up non-Knative resources
235-
resources := []client.Object{
236-
&corev1.Service{ObjectMeta: defaultMeta},
237-
&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: instance.Name + "-headless", Namespace: instance.Namespace}},
238-
&appsv1.Deployment{ObjectMeta: defaultMeta},
239-
&appsv1.StatefulSet{ObjectMeta: defaultMeta},
240-
&autoscalingv1.HorizontalPodAutoscaler{ObjectMeta: defaultMeta},
241-
}
242-
err = r.DeleteResources(resources)
180+
err = r.UpdateKnativeService(instance, defaultMeta, isKnativeSupported)
243181
if err != nil {
244-
reqLogger.Error(err, "Failed to clean up non-Knative resources")
245182
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
246-
}
247-
248-
if ok, _ := r.IsGroupVersionSupported(networkingv1.SchemeGroupVersion.String(), "Ingress"); ok {
249-
r.DeleteResource(&networkingv1.Ingress{ObjectMeta: defaultMeta})
250-
}
251-
252-
if r.IsOpenShift() {
253-
route := &routev1.Route{ObjectMeta: defaultMeta}
254-
err = r.DeleteResource(route)
255-
if err != nil {
256-
reqLogger.Error(err, "Failed to clean up non-Knative resource Route")
257-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
258-
}
259-
}
260-
261-
if isKnativeSupported {
262-
ksvc := &servingv1.Service{ObjectMeta: defaultMeta}
263-
err = r.CreateOrUpdate(ksvc, instance, func() error {
264-
appstacksutils.CustomizeKnativeService(ksvc, instance)
265-
return nil
266-
})
267-
268-
if err != nil {
269-
reqLogger.Error(err, "Failed to reconcile Knative Service")
270-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
271-
}
183+
} else {
272184
return r.ManageSuccess(common.StatusConditionTypeReconciled, instance)
273185
}
274-
return r.ManageError(errors.New("failed to reconcile Knative service as operator could not find Knative CRDs"), common.StatusConditionTypeReconciled, instance)
275186
}
276187

277188
if isKnativeSupported {
@@ -283,75 +194,25 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
283194
}
284195
}
285196

286-
useCertmanager, err := r.GenerateSvcCertSecret(ba, "rco", "Runtime Component Operator", "runtime-component-operator")
197+
useCertmanager, err := r.UpdateSvcCertSecret(instance, "rco", "Runtime Component Operator", "runtime-component-operator")
287198
if err != nil {
288-
reqLogger.Error(err, "Failed to reconcile CertManager Certificate")
289199
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
290200
}
291-
if ba.GetService().GetCertificateSecretRef() != nil {
292-
ba.GetStatus().SetReference(common.StatusReferenceCertSecretName, *ba.GetService().GetCertificateSecretRef())
293-
}
294201

295-
svc := &corev1.Service{ObjectMeta: defaultMeta}
296-
err = r.CreateOrUpdate(svc, instance, func() error {
297-
appstacksutils.CustomizeService(svc, ba)
298-
svc.Annotations = appstacksutils.MergeMaps(svc.Annotations, instance.Spec.Service.Annotations)
299-
if !useCertmanager && r.IsOpenShift() {
300-
appstacksutils.AddOCPCertAnnotation(ba, svc)
301-
}
302-
monitoringEnabledLabelName := getMonitoringEnabledLabelName(ba)
303-
if instance.Spec.Monitoring != nil {
304-
svc.Labels[monitoringEnabledLabelName] = "true"
305-
} else {
306-
delete(svc.Labels, monitoringEnabledLabelName)
307-
}
308-
return nil
309-
})
310-
if err != nil {
311-
reqLogger.Error(err, "Failed to reconcile Service")
202+
if err = r.UpdateService(instance, defaultMeta, useCertmanager); err != nil {
312203
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
313204
}
314205

315-
networkPolicy := &networkingv1.NetworkPolicy{ObjectMeta: defaultMeta}
316-
if np := instance.Spec.NetworkPolicy; !np.IsDisabled() {
317-
err = r.CreateOrUpdate(networkPolicy, instance, func() error {
318-
appstacksutils.CustomizeNetworkPolicy(networkPolicy, r.IsOpenShift(), instance)
319-
return nil
320-
})
321-
if err != nil {
322-
reqLogger.Error(err, "Failed to reconcile network policy")
323-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
324-
}
325-
} else {
326-
if err := r.DeleteResource(networkPolicy); err != nil {
327-
reqLogger.Error(err, "Failed to delete network policy")
328-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
329-
}
206+
if err = r.UpdateNetworkPolicy(instance, defaultMeta); err != nil {
207+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
330208
}
331209

332-
err = r.ReconcileBindings(instance)
333-
if err != nil {
334-
return r.ManageError(err, common.StatusConditionTypeReconciled, ba)
210+
if err = r.ReconcileBindings(instance); err != nil {
211+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
335212
}
336213

337214
if instance.Spec.StatefulSet != nil {
338-
// Delete Deployment if exists
339-
deploy := &appsv1.Deployment{ObjectMeta: defaultMeta}
340-
err = r.DeleteResource(deploy)
341-
342-
if err != nil {
343-
reqLogger.Error(err, "Failed to delete Deployment")
344-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
345-
}
346-
svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: instance.Name + "-headless", Namespace: instance.Namespace}}
347-
err = r.CreateOrUpdate(svc, instance, func() error {
348-
appstacksutils.CustomizeService(svc, instance)
349-
svc.Spec.ClusterIP = corev1.ClusterIPNone
350-
svc.Spec.Type = corev1.ServiceTypeClusterIP
351-
return nil
352-
})
353-
if err != nil {
354-
reqLogger.Error(err, "Failed to reconcile headless Service")
215+
if err = r.UpdateStatefulSetReq(instance, defaultMeta); err != nil {
355216
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
356217
}
357218

@@ -369,24 +230,11 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
369230
reqLogger.Error(err, "Failed to reconcile StatefulSet")
370231
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
371232
}
372-
373233
} else {
374-
// Delete StatefulSet if exists
375-
statefulSet := &appsv1.StatefulSet{ObjectMeta: defaultMeta}
376-
err = r.DeleteResource(statefulSet)
377-
if err != nil {
378-
reqLogger.Error(err, "Failed to delete Statefulset")
234+
if err = r.UpdateDeploymentReq(instance, defaultMeta); err != nil {
379235
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
380236
}
381237

382-
// Delete StatefulSet if exists
383-
headlesssvc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: instance.Name + "-headless", Namespace: instance.Namespace}}
384-
err = r.DeleteResource(headlesssvc)
385-
386-
if err != nil {
387-
reqLogger.Error(err, "Failed to delete headless Service")
388-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
389-
}
390238
deploy := &appsv1.Deployment{ObjectMeta: defaultMeta}
391239
err = r.CreateOrUpdate(deploy, instance, func() error {
392240
appstacksutils.CustomizeDeployment(deploy, instance)
@@ -400,79 +248,26 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
400248
reqLogger.Error(err, "Failed to reconcile Deployment")
401249
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
402250
}
403-
404251
}
405252

406-
if instance.Spec.Autoscaling != nil {
407-
hpa := &autoscalingv1.HorizontalPodAutoscaler{ObjectMeta: defaultMeta}
408-
err = r.CreateOrUpdate(hpa, instance, func() error {
409-
appstacksutils.CustomizeHPA(hpa, instance)
410-
return nil
411-
})
412-
413-
if err != nil {
414-
reqLogger.Error(err, "Failed to reconcile HorizontalPodAutoscaler")
415-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
416-
}
417-
} else {
418-
hpa := &autoscalingv1.HorizontalPodAutoscaler{ObjectMeta: defaultMeta}
419-
err = r.DeleteResource(hpa)
420-
if err != nil {
421-
reqLogger.Error(err, "Failed to delete HorizontalPodAutoscaler")
422-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
423-
}
253+
if err = r.UpdateAutoscaling(instance, defaultMeta); err != nil {
254+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
424255
}
425256

426257
if ok, err := r.IsGroupVersionSupported(routev1.SchemeGroupVersion.String(), "Route"); err != nil {
427258
reqLogger.Error(err, fmt.Sprintf("Failed to check if %s is supported", routev1.SchemeGroupVersion.String()))
428259
r.ManageError(err, common.StatusConditionTypeReconciled, instance)
429260
} else if ok {
430-
if instance.Spec.Expose != nil && *instance.Spec.Expose {
431-
route := &routev1.Route{ObjectMeta: defaultMeta}
432-
err = r.CreateOrUpdate(route, instance, func() error {
433-
key, cert, caCert, destCACert, err := r.GetRouteTLSValues(ba)
434-
if err != nil {
435-
return err
436-
}
437-
appstacksutils.CustomizeRoute(route, ba, key, cert, caCert, destCACert)
438-
439-
return nil
440-
})
441-
if err != nil {
442-
reqLogger.Error(err, "Failed to reconcile Route")
443-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
444-
}
445-
} else {
446-
route := &routev1.Route{ObjectMeta: defaultMeta}
447-
err = r.DeleteResource(route)
448-
if err != nil {
449-
reqLogger.Error(err, "Failed to delete Route")
450-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
451-
}
261+
if err = r.UpdateRoute(instance, defaultMeta); err != nil {
262+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
452263
}
453264
} else {
454-
455265
if ok, err := r.IsGroupVersionSupported(networkingv1.SchemeGroupVersion.String(), "Ingress"); err != nil {
456266
reqLogger.Error(err, fmt.Sprintf("Failed to check if %s is supported", networkingv1.SchemeGroupVersion.String()))
457267
r.ManageError(err, common.StatusConditionTypeReconciled, instance)
458268
} else if ok {
459-
if instance.Spec.Expose != nil && *instance.Spec.Expose {
460-
ing := &networkingv1.Ingress{ObjectMeta: defaultMeta}
461-
err = r.CreateOrUpdate(ing, instance, func() error {
462-
appstacksutils.CustomizeIngress(ing, instance)
463-
return nil
464-
})
465-
if err != nil {
466-
reqLogger.Error(err, "Failed to reconcile Ingress")
467-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
468-
}
469-
} else {
470-
ing := &networkingv1.Ingress{ObjectMeta: defaultMeta}
471-
err = r.DeleteResource(ing)
472-
if err != nil {
473-
reqLogger.Error(err, "Failed to delete Ingress")
474-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
475-
}
269+
if err = r.UpdateIngress(instance, defaultMeta); err != nil {
270+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
476271
}
477272
}
478273
}
@@ -481,25 +276,9 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
481276
reqLogger.Error(err, fmt.Sprintf("Failed to check if %s is supported", prometheusv1.SchemeGroupVersion.String()))
482277
r.ManageError(err, common.StatusConditionTypeReconciled, instance)
483278
} else if ok {
484-
if instance.Spec.Monitoring != nil && (instance.Spec.CreateKnativeService == nil || !*instance.Spec.CreateKnativeService) {
485-
sm := &prometheusv1.ServiceMonitor{ObjectMeta: defaultMeta}
486-
err = r.CreateOrUpdate(sm, instance, func() error {
487-
appstacksutils.CustomizeServiceMonitor(sm, instance)
488-
return nil
489-
})
490-
if err != nil {
491-
reqLogger.Error(err, "Failed to reconcile ServiceMonitor")
492-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
493-
}
494-
} else {
495-
sm := &prometheusv1.ServiceMonitor{ObjectMeta: defaultMeta}
496-
err = r.DeleteResource(sm)
497-
if err != nil {
498-
reqLogger.Error(err, "Failed to delete ServiceMonitor")
499-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
500-
}
279+
if err = r.UpdateServiceMonitor(instance, defaultMeta); err != nil {
280+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
501281
}
502-
503282
} else {
504283
reqLogger.V(1).Info(fmt.Sprintf("%s is not supported", prometheusv1.SchemeGroupVersion.String()))
505284
}

0 commit comments

Comments
 (0)