Skip to content

Commit

Permalink
feat: suspend feature
Browse files Browse the repository at this point in the history
Signed-off-by: peefy <[email protected]>
  • Loading branch information
Peefy committed Aug 20, 2024
1 parent 4287dc7 commit f9574cf
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 5 deletions.
12 changes: 9 additions & 3 deletions api/v1alpha1/kclrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,15 @@ type ConfigSpec struct {

// KCLRunStatus defines the observed state of KCLRun
type KCLRunStatus struct {
meta.ReconcileRequestStatus `json:",inline"`

// ObservedGeneration is the last reconciled generation.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`

// +optional
Conditions []metav1.Condition `json:"conditions,omitempty"`

// The last successfully applied revision.
// Equals the Revision of the applied Artifact from the referenced Source.
// +optional
Expand All @@ -208,9 +217,6 @@ type KCLRunStatus struct {
// +optional
LastAttemptedRevisionDigest string `json:"lastAttemptedRevisionDigest,omitempty"`

// +optional
Conditions []metav1.Condition `json:"conditions,omitempty"`

// Inventory contains the list of Kubernetes resource object references that
// have been successfully applied.
// +optional
Expand Down
10 changes: 10 additions & 0 deletions config/crd/bases/krm.kcl.dev.fluxcd_kclruns.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,16 @@ spec:
LastAttemptedRevisionDigest is the digest of the last reconciliation attempt.
This is only set for OCIRepository sources.
type: string
lastHandledReconcileAt:
description: |-
LastHandledReconcileAt holds the value of the most recent
reconcile request value, so a change of the annotation value
can be detected.
type: string
observedGeneration:
description: ObservedGeneration is the last reconciled generation.
format: int64
type: integer
type: object
type: object
served: true
Expand Down
77 changes: 75 additions & 2 deletions internal/controller/kclrun_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ func (r *KCLRunReconciler) SetupWithManager(mgr ctrl.Manager, opts KCLRunReconci
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
func (r *KCLRunReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
func (r *KCLRunReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) {
log := ctrl.LoggerFrom(ctx)

reconcileStart := time.Now()
// Get KCL source object
var obj v1alpha1.KCLRun
if err := r.Get(ctx, req.NamespacedName, &obj); err != nil {
Expand All @@ -150,6 +150,51 @@ func (r *KCLRunReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
// Initialize the runtime patcher with the current version of the object.
patcher := patch.NewSerialPatcher(&obj, r.Client)

// Finalise the reconciliation and report the results.
defer func() {
// Patch finalizers, status and conditions.
if err := r.finalizeStatus(ctx, &obj, patcher); err != nil {
retErr = kerrors.NewAggregate([]error{retErr, err})
}

// Record Prometheus metrics.
r.Metrics.RecordReadiness(ctx, &obj)
r.Metrics.RecordDuration(ctx, &obj, reconcileStart)
r.Metrics.RecordSuspend(ctx, &obj, obj.Spec.Suspend)

// Log and emit success event.
if conditions.IsReady(&obj) {
msg := fmt.Sprintf("Reconciliation finished in %s, next run in %s",
time.Since(reconcileStart).String(),
obj.Spec.Interval.Duration.String())
log.Info(msg, "revision", obj.Status.LastAttemptedRevision)
r.event(&obj, obj.Status.LastAppliedRevision, eventv1.EventSeverityInfo, msg,
map[string]string{
v1alpha1.GroupVersion.Group + "/" + eventv1.MetaCommitStatusKey: eventv1.MetaCommitStatusUpdateValue,
})
}
}()

// Prune managed resources if the object is under deletion.
if !obj.ObjectMeta.DeletionTimestamp.IsZero() {
return r.finalize(ctx, &obj)
}

// Add finalizer first if it doesn't exist to avoid the race condition
// between init and delete.
// Note: Finalizers in general can only be added when the deletionTimestamp
// is not set.
if !controllerutil.ContainsFinalizer(&obj, v1alpha1.KCLRunFinalizer) {
controllerutil.AddFinalizer(&obj, v1alpha1.KCLRunFinalizer)
return ctrl.Result{Requeue: true}, nil
}

// Skip reconciliation if the object is suspended.
if obj.Spec.Suspend {
log.Info("Reconciliation is suspended for this object")
return ctrl.Result{}, nil
}

source, err := r.getSource(ctx, &obj)
if err != nil {
conditions.MarkFalse(&obj, meta.ReadyCondition, meta.ArtifactFailedReason, "%s", err)
Expand Down Expand Up @@ -833,6 +878,34 @@ func (r *KCLRunReconciler) apply(ctx context.Context,
return applyLog != "", resultSet, nil
}

func (r *KCLRunReconciler) finalizeStatus(ctx context.Context,
obj *v1alpha1.KCLRun,
patcher *patch.SerialPatcher) error {
// Set the value of the reconciliation request in status.
if v, ok := meta.ReconcileAnnotationValue(obj.GetAnnotations()); ok {
obj.Status.LastHandledReconcileAt = v
}

// Remove the Reconciling condition and update the observed generation
// if the reconciliation was successful.
if conditions.IsTrue(obj, meta.ReadyCondition) {
conditions.Delete(obj, meta.ReconcilingCondition)
obj.Status.ObservedGeneration = obj.Generation
}

// Set the Reconciling reason to ProgressingWithRetry if the
// reconciliation has failed.
if conditions.IsFalse(obj, meta.ReadyCondition) &&
conditions.Has(obj, meta.ReconcilingCondition) {
rc := conditions.Get(obj, meta.ReconcilingCondition)
rc.Reason = meta.ProgressingWithRetryReason
conditions.Set(obj, rc)
}

// Patch finalizers, status and conditions.
return r.patch(ctx, obj, patcher)
}

func (r *KCLRunReconciler) patch(ctx context.Context,
obj *v1alpha1.KCLRun,
patcher *patch.SerialPatcher) (retErr error) {
Expand Down

0 comments on commit f9574cf

Please sign in to comment.