Skip to content

Commit 3e561f6

Browse files
committed
Share controller code further
1 parent 3dc19ed commit 3e561f6

3 files changed

Lines changed: 401 additions & 236 deletions

File tree

common/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ type BaseComponentService interface {
129129
type BaseComponentNetworkPolicy interface {
130130
GetNamespaceLabels() map[string]string
131131
GetFromLabels() map[string]string
132+
IsDisabled() bool
132133
}
133134

134135
// BaseComponentMonitoring represents basic service monitoring configuration

controllers/runtimecomponent_controller.go

Lines changed: 25 additions & 236 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"context"
2121
"fmt"
2222
"os"
23-
"strings"
2423

2524
"github.com/application-stacks/runtime-component-operator/common"
2625
"github.com/pkg/errors"
@@ -50,7 +49,6 @@ import (
5049
networkingv1 "k8s.io/api/networking/v1"
5150
kerrors "k8s.io/apimachinery/pkg/api/errors"
5251
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
53-
"k8s.io/apimachinery/pkg/types"
5452
servingv1 "knative.dev/serving/pkg/apis/serving/v1"
5553
"sigs.k8s.io/controller-runtime/pkg/client"
5654
)
@@ -87,7 +85,7 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
8785

8886
ns, err := appstacksutils.GetOperatorNamespace()
8987
// When running the operator locally, `ns` will be empty string
90-
if ns == "" {
88+
if err != nil || ns == "" {
9189
// Since this method can be called directly from unit test, populate `watchNamespaces`.
9290
if r.watchNamespaces == nil {
9391
r.watchNamespaces, err = appstacksutils.GetWatchNamespaces()
@@ -122,7 +120,7 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
122120

123121
// Fetch the RuntimeComponent instance
124122
instance := &appstacksv1beta2.RuntimeComponent{}
125-
var ba common.BaseComponent = instance
123+
// var ba common.BaseComponent = instance
126124
err = r.GetClient().Get(context.TODO(), req.NamespacedName, instance)
127125
if err != nil {
128126
if kerrors.IsNotFound(err) {
@@ -167,57 +165,13 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
167165
Namespace: instance.Namespace,
168166
}
169167

170-
imageReferenceOld := instance.Status.ImageReference
171-
instance.Status.ImageReference = instance.Spec.ApplicationImage
172-
if r.IsOpenShift() {
173-
image, err := imageutil.ParseDockerImageReference(instance.Spec.ApplicationImage)
174-
if err == nil {
175-
isTag := &imagev1.ImageStreamTag{}
176-
isTagName := imageutil.JoinImageStreamTag(image.Name, image.Tag)
177-
isTagNamespace := image.Namespace
178-
if isTagNamespace == "" {
179-
isTagNamespace = instance.Namespace
180-
}
181-
key := types.NamespacedName{Name: isTagName, Namespace: isTagNamespace}
182-
err = r.GetAPIReader().Get(context.Background(), key, isTag)
183-
// Call ManageError only if the error type is not found or is not forbidden. Forbidden could happen
184-
// when the operator tries to call GET for ImageStreamTags on a namespace that doesn't exists (e.g.
185-
// cannot get imagestreamtags.image.openshift.io in the namespace "navidsh": no RBAC policy matched)
186-
if err == nil {
187-
image := isTag.Image
188-
if image.DockerImageReference != "" {
189-
instance.Status.ImageReference = image.DockerImageReference
190-
}
191-
} else if err != nil && !kerrors.IsNotFound(err) && !kerrors.IsForbidden(err) && !strings.Contains(isTagName, "/") {
192-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
193-
}
194-
}
195-
}
196-
if imageReferenceOld != instance.Status.ImageReference {
197-
reqLogger.Info("Updating status.imageReference", "status.imageReference", instance.Status.ImageReference)
198-
err = r.UpdateStatus(instance)
199-
if err != nil {
200-
reqLogger.Error(err, "Error updating RuntimeComponent status")
201-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
202-
}
168+
if err = r.UpdateImageReference(instance); err != nil {
169+
reqLogger.Error(err, "Error updating RuntimeComponent")
170+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
203171
}
204172

205-
if instance.Spec.ServiceAccountName == nil || *instance.Spec.ServiceAccountName == "" {
206-
serviceAccount := &corev1.ServiceAccount{ObjectMeta: defaultMeta}
207-
err = r.CreateOrUpdate(serviceAccount, instance, func() error {
208-
return appstacksutils.CustomizeServiceAccount(serviceAccount, instance, r.GetClient())
209-
})
210-
if err != nil {
211-
reqLogger.Error(err, "Failed to reconcile ServiceAccount")
212-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
213-
}
214-
} else {
215-
serviceAccount := &corev1.ServiceAccount{ObjectMeta: defaultMeta}
216-
err = r.DeleteResource(serviceAccount)
217-
if err != nil {
218-
reqLogger.Error(err, "Failed to delete ServiceAccount")
219-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
220-
}
173+
if err = r.UpdateServiceAccount(instance, defaultMeta); err != nil {
174+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
221175
}
222176

223177
// Check if the ServiceAccount has a valid pull secret before creating the deployment/statefulset
@@ -235,44 +189,10 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
235189
}
236190

237191
if instance.Spec.CreateKnativeService != nil && *instance.Spec.CreateKnativeService {
238-
// Clean up non-Knative resources
239-
resources := []client.Object{
240-
&corev1.Service{ObjectMeta: defaultMeta},
241-
&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: instance.Name + "-headless", Namespace: instance.Namespace}},
242-
&appsv1.Deployment{ObjectMeta: defaultMeta},
243-
&appsv1.StatefulSet{ObjectMeta: defaultMeta},
244-
&autoscalingv1.HorizontalPodAutoscaler{ObjectMeta: defaultMeta},
245-
}
246-
err = r.DeleteResources(resources)
192+
err = r.UpdateKnativeService(instance, defaultMeta, isKnativeSupported)
247193
if err != nil {
248-
reqLogger.Error(err, "Failed to clean up non-Knative resources")
249194
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
250-
}
251-
252-
if ok, _ := r.IsGroupVersionSupported(networkingv1.SchemeGroupVersion.String(), "Ingress"); ok {
253-
r.DeleteResource(&networkingv1.Ingress{ObjectMeta: defaultMeta})
254-
}
255-
256-
if r.IsOpenShift() {
257-
route := &routev1.Route{ObjectMeta: defaultMeta}
258-
err = r.DeleteResource(route)
259-
if err != nil {
260-
reqLogger.Error(err, "Failed to clean up non-Knative resource Route")
261-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
262-
}
263-
}
264-
265-
if isKnativeSupported {
266-
ksvc := &servingv1.Service{ObjectMeta: defaultMeta}
267-
err = r.CreateOrUpdate(ksvc, instance, func() error {
268-
appstacksutils.CustomizeKnativeService(ksvc, instance)
269-
return nil
270-
})
271-
272-
if err != nil {
273-
reqLogger.Error(err, "Failed to reconcile Knative Service")
274-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
275-
}
195+
} else {
276196
return r.ManageSuccess(common.StatusConditionTypeReconciled, instance)
277197
}
278198
return r.ManageError(errors.New("failed to reconcile Knative service as operator could not find Knative CRDs"), common.StatusConditionTypeReconciled, instance)
@@ -287,75 +207,25 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
287207
}
288208
}
289209

290-
useCertmanager, err := r.GenerateSvcCertSecret(ba, "rco", "Runtime Component Operator", "runtime-component-operator")
210+
useCertmanager, err := r.UpdateSvcCertSecret(instance, "rco", "Runtime Component Operator", "runtime-component-operator")
291211
if err != nil {
292-
reqLogger.Error(err, "Failed to reconcile CertManager Certificate")
293212
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
294213
}
295-
if ba.GetService().GetCertificateSecretRef() != nil {
296-
ba.GetStatus().SetReference(common.StatusReferenceCertSecretName, *ba.GetService().GetCertificateSecretRef())
297-
}
298214

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

319-
networkPolicy := &networkingv1.NetworkPolicy{ObjectMeta: defaultMeta}
320-
if np := instance.Spec.NetworkPolicy; !np.IsDisabled() {
321-
err = r.CreateOrUpdate(networkPolicy, instance, func() error {
322-
appstacksutils.CustomizeNetworkPolicy(networkPolicy, r.IsOpenShift(), instance)
323-
return nil
324-
})
325-
if err != nil {
326-
reqLogger.Error(err, "Failed to reconcile network policy")
327-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
328-
}
329-
} else {
330-
if err := r.DeleteResource(networkPolicy); err != nil {
331-
reqLogger.Error(err, "Failed to delete network policy")
332-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
333-
}
219+
if err = r.UpdateNetworkPolicy(instance, defaultMeta); err != nil {
220+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
334221
}
335222

336-
err = r.ReconcileBindings(instance)
337-
if err != nil {
338-
return r.ManageError(err, common.StatusConditionTypeReconciled, ba)
223+
if err = r.ReconcileBindings(instance); err != nil {
224+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
339225
}
340226

341227
if instance.Spec.StatefulSet != nil {
342-
// Delete Deployment if exists
343-
deploy := &appsv1.Deployment{ObjectMeta: defaultMeta}
344-
err = r.DeleteResource(deploy)
345-
346-
if err != nil {
347-
reqLogger.Error(err, "Failed to delete Deployment")
348-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
349-
}
350-
svc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: instance.Name + "-headless", Namespace: instance.Namespace}}
351-
err = r.CreateOrUpdate(svc, instance, func() error {
352-
appstacksutils.CustomizeService(svc, instance)
353-
svc.Spec.ClusterIP = corev1.ClusterIPNone
354-
svc.Spec.Type = corev1.ServiceTypeClusterIP
355-
return nil
356-
})
357-
if err != nil {
358-
reqLogger.Error(err, "Failed to reconcile headless Service")
228+
if err = r.UpdateStatefulSetReq(instance, defaultMeta); err != nil {
359229
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
360230
}
361231

@@ -375,22 +245,10 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
375245
}
376246

377247
} else {
378-
// Delete StatefulSet if exists
379-
statefulSet := &appsv1.StatefulSet{ObjectMeta: defaultMeta}
380-
err = r.DeleteResource(statefulSet)
381-
if err != nil {
382-
reqLogger.Error(err, "Failed to delete Statefulset")
248+
if err = r.UpdateDeploymentReq(instance, defaultMeta); err != nil {
383249
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
384250
}
385251

386-
// Delete StatefulSet if exists
387-
headlesssvc := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: instance.Name + "-headless", Namespace: instance.Namespace}}
388-
err = r.DeleteResource(headlesssvc)
389-
390-
if err != nil {
391-
reqLogger.Error(err, "Failed to delete headless Service")
392-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
393-
}
394252
deploy := &appsv1.Deployment{ObjectMeta: defaultMeta}
395253
err = r.CreateOrUpdate(deploy, instance, func() error {
396254
appstacksutils.CustomizeDeployment(deploy, instance)
@@ -404,79 +262,26 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
404262
reqLogger.Error(err, "Failed to reconcile Deployment")
405263
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
406264
}
407-
408265
}
409266

410-
if instance.Spec.Autoscaling != nil {
411-
hpa := &autoscalingv1.HorizontalPodAutoscaler{ObjectMeta: defaultMeta}
412-
err = r.CreateOrUpdate(hpa, instance, func() error {
413-
appstacksutils.CustomizeHPA(hpa, instance)
414-
return nil
415-
})
416-
417-
if err != nil {
418-
reqLogger.Error(err, "Failed to reconcile HorizontalPodAutoscaler")
419-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
420-
}
421-
} else {
422-
hpa := &autoscalingv1.HorizontalPodAutoscaler{ObjectMeta: defaultMeta}
423-
err = r.DeleteResource(hpa)
424-
if err != nil {
425-
reqLogger.Error(err, "Failed to delete HorizontalPodAutoscaler")
426-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
427-
}
267+
if err = r.UpdateAutoscaling(instance, defaultMeta); err != nil {
268+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
428269
}
429270

430271
if ok, err := r.IsGroupVersionSupported(routev1.SchemeGroupVersion.String(), "Route"); err != nil {
431272
reqLogger.Error(err, fmt.Sprintf("Failed to check if %s is supported", routev1.SchemeGroupVersion.String()))
432273
r.ManageError(err, common.StatusConditionTypeReconciled, instance)
433274
} else if ok {
434-
if instance.Spec.Expose != nil && *instance.Spec.Expose {
435-
route := &routev1.Route{ObjectMeta: defaultMeta}
436-
err = r.CreateOrUpdate(route, instance, func() error {
437-
key, cert, caCert, destCACert, err := r.GetRouteTLSValues(ba)
438-
if err != nil {
439-
return err
440-
}
441-
appstacksutils.CustomizeRoute(route, ba, key, cert, caCert, destCACert)
442-
443-
return nil
444-
})
445-
if err != nil {
446-
reqLogger.Error(err, "Failed to reconcile Route")
447-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
448-
}
449-
} else {
450-
route := &routev1.Route{ObjectMeta: defaultMeta}
451-
err = r.DeleteResource(route)
452-
if err != nil {
453-
reqLogger.Error(err, "Failed to delete Route")
454-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
455-
}
275+
if err = r.UpdateRoute(instance, defaultMeta); err != nil {
276+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
456277
}
457278
} else {
458-
459279
if ok, err := r.IsGroupVersionSupported(networkingv1.SchemeGroupVersion.String(), "Ingress"); err != nil {
460280
reqLogger.Error(err, fmt.Sprintf("Failed to check if %s is supported", networkingv1.SchemeGroupVersion.String()))
461281
r.ManageError(err, common.StatusConditionTypeReconciled, instance)
462282
} else if ok {
463-
if instance.Spec.Expose != nil && *instance.Spec.Expose {
464-
ing := &networkingv1.Ingress{ObjectMeta: defaultMeta}
465-
err = r.CreateOrUpdate(ing, instance, func() error {
466-
appstacksutils.CustomizeIngress(ing, instance)
467-
return nil
468-
})
469-
if err != nil {
470-
reqLogger.Error(err, "Failed to reconcile Ingress")
471-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
472-
}
473-
} else {
474-
ing := &networkingv1.Ingress{ObjectMeta: defaultMeta}
475-
err = r.DeleteResource(ing)
476-
if err != nil {
477-
reqLogger.Error(err, "Failed to delete Ingress")
478-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
479-
}
283+
if err = r.UpdateIngress(instance, defaultMeta); err != nil {
284+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
480285
}
481286
}
482287
}
@@ -485,25 +290,9 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
485290
reqLogger.Error(err, fmt.Sprintf("Failed to check if %s is supported", prometheusv1.SchemeGroupVersion.String()))
486291
r.ManageError(err, common.StatusConditionTypeReconciled, instance)
487292
} else if ok {
488-
if instance.Spec.Monitoring != nil && (instance.Spec.CreateKnativeService == nil || !*instance.Spec.CreateKnativeService) {
489-
sm := &prometheusv1.ServiceMonitor{ObjectMeta: defaultMeta}
490-
err = r.CreateOrUpdate(sm, instance, func() error {
491-
appstacksutils.CustomizeServiceMonitor(sm, instance)
492-
return nil
493-
})
494-
if err != nil {
495-
reqLogger.Error(err, "Failed to reconcile ServiceMonitor")
496-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
497-
}
498-
} else {
499-
sm := &prometheusv1.ServiceMonitor{ObjectMeta: defaultMeta}
500-
err = r.DeleteResource(sm)
501-
if err != nil {
502-
reqLogger.Error(err, "Failed to delete ServiceMonitor")
503-
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
504-
}
293+
if err = r.UpdateServiceMonitor(instance, defaultMeta); err != nil {
294+
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
505295
}
506-
507296
} else {
508297
reqLogger.V(1).Info(fmt.Sprintf("%s is not supported", prometheusv1.SchemeGroupVersion.String()))
509298
}

0 commit comments

Comments
 (0)