@@ -33,10 +33,12 @@ import (
3333 "github.com/go-git/go-git/v5/plumbing/transport"
3434 "github.com/go-logr/logr"
3535 corev1 "k8s.io/api/core/v1"
36+ apimeta "k8s.io/apimachinery/pkg/api/meta"
3637 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3738 "k8s.io/apimachinery/pkg/runtime"
3839 "k8s.io/apimachinery/pkg/types"
3940 kuberecorder "k8s.io/client-go/tools/record"
41+ "k8s.io/client-go/tools/reference"
4042 ctrl "sigs.k8s.io/controller-runtime"
4143 "sigs.k8s.io/controller-runtime/pkg/client"
4244 "sigs.k8s.io/controller-runtime/pkg/handler"
@@ -46,6 +48,7 @@ import (
4648 imagev1_reflect "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
4749 "github.com/fluxcd/pkg/apis/meta"
4850 "github.com/fluxcd/pkg/runtime/events"
51+ "github.com/fluxcd/pkg/runtime/metrics"
4952 "github.com/fluxcd/pkg/runtime/predicates"
5053 sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
5154 "github.com/fluxcd/source-controller/pkg/git"
@@ -68,9 +71,10 @@ const imagePolicyKey = ".spec.update.imagePolicy"
6871// ImageUpdateAutomationReconciler reconciles a ImageUpdateAutomation object
6972type ImageUpdateAutomationReconciler struct {
7073 client.Client
71- Log logr.Logger
72- Scheme * runtime.Scheme
73- EventRecorder kuberecorder.EventRecorder
74+ Log logr.Logger
75+ Scheme * runtime.Scheme
76+ EventRecorder kuberecorder.EventRecorder
77+ MetricsRecorder * metrics.Recorder
7478}
7579
7680// +kubebuilder:rbac:groups=image.toolkit.fluxcd.io,resources=imageupdateautomations,verbs=get;list;watch;create;update;patch;delete
@@ -92,6 +96,19 @@ func (r *ImageUpdateAutomationReconciler) Reconcile(req ctrl.Request) (ctrl.Resu
9296 return ctrl.Result {}, nil
9397 }
9498
99+ // Record readiness metric when exiting; if there's any points at
100+ // which the readiness is updated _without also exiting_, they
101+ // should also record the readiness.
102+ defer r .recordReadinessMetric (& auto )
103+ // Record reconciliation duration when exiting
104+ if r .MetricsRecorder != nil {
105+ objRef , err := reference .GetReference (r .Scheme , & auto )
106+ if err != nil {
107+ return ctrl.Result {}, err
108+ }
109+ defer r .MetricsRecorder .RecordDuration (* objRef , now )
110+ }
111+
95112 // whatever else happens, we've now "seen" the reconcile
96113 // annotation if it's there
97114 if token , ok := meta .ReconcileAnnotationValue (auto .GetAnnotations ()); ok {
@@ -359,14 +376,37 @@ func commitAllAndPush(ctx context.Context, repo *gogit.Repository, access repoAc
359376 })
360377}
361378
362- // --- events
379+ // --- events, metrics
363380
364381func (r * ImageUpdateAutomationReconciler ) event (auto imagev1.ImageUpdateAutomation , severity , msg string ) {
365382 if r .EventRecorder != nil {
366383 r .EventRecorder .Event (& auto , "Normal" , severity , msg )
367384 }
368385}
369386
387+ func (r * ImageUpdateAutomationReconciler ) recordReadinessMetric (auto * imagev1.ImageUpdateAutomation ) {
388+ if r .MetricsRecorder == nil {
389+ return
390+ }
391+
392+ objRef , err := reference .GetReference (r .Scheme , auto )
393+ if err != nil {
394+ r .Log .WithValues (
395+ strings .ToLower (auto .Kind ),
396+ fmt .Sprintf ("%s/%s" , auto .GetNamespace (), auto .GetName ()),
397+ ).Error (err , "unable to record readiness metric" )
398+ return
399+ }
400+ if rc := apimeta .FindStatusCondition (auto .Status .Conditions , meta .ReadyCondition ); rc != nil {
401+ r .MetricsRecorder .RecordCondition (* objRef , * rc , ! auto .DeletionTimestamp .IsZero ())
402+ } else {
403+ r .MetricsRecorder .RecordCondition (* objRef , metav1.Condition {
404+ Type : meta .ReadyCondition ,
405+ Status : metav1 .ConditionUnknown ,
406+ }, ! auto .DeletionTimestamp .IsZero ())
407+ }
408+ }
409+
370410// --- updates
371411
372412// updateAccordingToSetters updates files under the root by treating
0 commit comments