Skip to content

Commit 3d6a5e1

Browse files
committed
Add progressive status in helmrepo reconciler
Signed-off-by: Sunny <[email protected]>
1 parent ccf0b62 commit 3d6a5e1

File tree

2 files changed

+203
-46
lines changed

2 files changed

+203
-46
lines changed

controllers/helmrepository_controller.go

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import (
4343
helper "github.com/fluxcd/pkg/runtime/controller"
4444
"github.com/fluxcd/pkg/runtime/patch"
4545
"github.com/fluxcd/pkg/runtime/predicates"
46+
rreconcile "github.com/fluxcd/pkg/runtime/reconcile"
4647

4748
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
4849
"github.com/fluxcd/source-controller/internal/cache"
@@ -109,6 +110,8 @@ type HelmRepositoryReconciler struct {
109110
Cache *cache.Cache
110111
TTL time.Duration
111112
*cache.CacheRecorder
113+
114+
patchOptions []patch.Option
112115
}
113116

114117
type HelmRepositoryReconcilerOptions struct {
@@ -120,13 +123,15 @@ type HelmRepositoryReconcilerOptions struct {
120123
// v1beta2.HelmRepository (sub)reconcile functions. The type implementations
121124
// are grouped and executed serially to perform the complete reconcile of the
122125
// object.
123-
type helmRepositoryReconcileFunc func(ctx context.Context, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error)
126+
type helmRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error)
124127

125128
func (r *HelmRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error {
126129
return r.SetupWithManagerAndOptions(mgr, HelmRepositoryReconcilerOptions{})
127130
}
128131

129132
func (r *HelmRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts HelmRepositoryReconcilerOptions) error {
133+
r.patchOptions = getPatchOptions(helmRepositoryReadyCondition.Owned, r.ControllerName)
134+
130135
return ctrl.NewControllerManagedBy(mgr).
131136
For(&sourcev1.HelmRepository{}).
132137
WithEventFilter(
@@ -160,18 +165,15 @@ func (r *HelmRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reque
160165
r.RecordSuspend(ctx, obj, obj.Spec.Suspend)
161166

162167
// Initialize the patch helper with the current version of the object.
163-
patchHelper, err := patch.NewHelper(obj, r.Client)
164-
if err != nil {
165-
return ctrl.Result{}, err
166-
}
168+
serialPatcher := patch.NewSerialPatcher(obj, r.Client)
167169

168170
// recResult stores the abstracted reconcile result.
169171
var recResult sreconcile.Result
170172

171173
// Always attempt to patch the object after each reconciliation.
172174
// NOTE: The final runtime result and error are set in this block.
173175
defer func() {
174-
summarizeHelper := summarize.NewHelper(r.EventRecorder, patchHelper)
176+
summarizeHelper := summarize.NewHelper(r.EventRecorder, serialPatcher)
175177
summarizeOpts := []summarize.Option{
176178
summarize.WithConditions(helmRepositoryReadyCondition),
177179
summarize.WithReconcileResult(recResult),
@@ -219,19 +221,36 @@ func (r *HelmRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reque
219221
r.reconcileSource,
220222
r.reconcileArtifact,
221223
}
222-
recResult, retErr = r.reconcile(ctx, obj, reconcilers)
224+
recResult, retErr = r.reconcile(ctx, serialPatcher, obj, reconcilers)
223225
return
224226
}
225227

226228
// reconcile iterates through the helmRepositoryReconcileFunc tasks for the
227229
// object. It returns early on the first call that returns
228230
// reconcile.ResultRequeue, or produces an error.
229-
func (r *HelmRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.HelmRepository, reconcilers []helmRepositoryReconcileFunc) (sreconcile.Result, error) {
231+
func (r *HelmRepositoryReconciler) reconcile(ctx context.Context, sp *patch.SerialPatcher,
232+
obj *sourcev1.HelmRepository, reconcilers []helmRepositoryReconcileFunc) (sreconcile.Result, error) {
230233
oldObj := obj.DeepCopy()
231234

232-
// Mark as reconciling if generation differs.
233-
if obj.Generation != obj.Status.ObservedGeneration {
234-
conditions.MarkReconciling(obj, "NewGeneration", "reconciling new object generation (%d)", obj.Generation)
235+
rreconcile.ProgressiveStatus(false, obj, meta.ProgressingReason, "reconciliation in progress")
236+
237+
var reconcileAtVal string
238+
if v, ok := meta.ReconcileAnnotationValue(obj.GetAnnotations()); ok {
239+
reconcileAtVal = v
240+
}
241+
242+
// Persist reconciling if generation differs or reconciliation is requested.
243+
switch {
244+
case obj.Generation != obj.Status.ObservedGeneration:
245+
rreconcile.ProgressiveStatus(false, obj, meta.ProgressingReason,
246+
"processing object: new generation %d -> %d", obj.Status.ObservedGeneration, obj.Generation)
247+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
248+
return sreconcile.ResultEmpty, err
249+
}
250+
case reconcileAtVal != obj.Status.GetLastHandledReconcileRequest():
251+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
252+
return sreconcile.ResultEmpty, err
253+
}
235254
}
236255

237256
var chartRepo repository.ChartRepository
@@ -241,7 +260,7 @@ func (r *HelmRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.
241260
var res sreconcile.Result
242261
var resErr error
243262
for _, rec := range reconcilers {
244-
recResult, err := rec(ctx, obj, &artifact, &chartRepo)
263+
recResult, err := rec(ctx, sp, obj, &artifact, &chartRepo)
245264
// Exit immediately on ResultRequeue.
246265
if recResult == sreconcile.ResultRequeue {
247266
return sreconcile.ResultRequeue, nil
@@ -311,22 +330,32 @@ func (r *HelmRepositoryReconciler) notify(ctx context.Context, oldObj, newObj *s
311330
// condition is added.
312331
// The hostname of any URL in the Status of the object are updated, to ensure
313332
// they match the Storage server hostname of current runtime.
314-
func (r *HelmRepositoryReconciler) reconcileStorage(ctx context.Context, obj *sourcev1.HelmRepository, _ *sourcev1.Artifact, _ *repository.ChartRepository) (sreconcile.Result, error) {
333+
func (r *HelmRepositoryReconciler) reconcileStorage(ctx context.Context, sp *patch.SerialPatcher,
334+
obj *sourcev1.HelmRepository, _ *sourcev1.Artifact, _ *repository.ChartRepository) (sreconcile.Result, error) {
315335
// Garbage collect previous advertised artifact(s) from storage
316336
_ = r.garbageCollect(ctx, obj)
317337

318338
// Determine if the advertised artifact is still in storage
339+
var artifactMissing bool
319340
if artifact := obj.GetArtifact(); artifact != nil && !r.Storage.ArtifactExist(*artifact) {
320341
obj.Status.Artifact = nil
321342
obj.Status.URL = ""
343+
artifactMissing = true
322344
// Remove the condition as the artifact doesn't exist.
323345
conditions.Delete(obj, sourcev1.ArtifactInStorageCondition)
324346
}
325347

326348
// Record that we do not have an artifact
327349
if obj.GetArtifact() == nil {
328-
conditions.MarkReconciling(obj, "NoArtifact", "no artifact for resource in storage")
350+
msg := "building artifact"
351+
if artifactMissing {
352+
msg += ": disappeared from storage"
353+
}
354+
rreconcile.ProgressiveStatus(true, obj, meta.ProgressingReason, msg)
329355
conditions.Delete(obj, sourcev1.ArtifactInStorageCondition)
356+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
357+
return sreconcile.ResultEmpty, err
358+
}
330359
return sreconcile.ResultSuccess, nil
331360
}
332361

@@ -346,7 +375,8 @@ func (r *HelmRepositoryReconciler) reconcileStorage(ctx context.Context, obj *so
346375
// If successful and the index is valid, any previous
347376
// v1beta2.FetchFailedCondition is removed, and the repository.ChartRepository
348377
// pointer is set to the newly fetched index.
349-
func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) {
378+
func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher,
379+
obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) {
350380
var tlsConfig *tls.Config
351381

352382
// Configure Helm client to access repository
@@ -455,8 +485,14 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
455485
// Mark observations about the revision on the object.
456486
if !obj.GetArtifact().HasRevision(chartRepo.Checksum) {
457487
message := fmt.Sprintf("new index revision '%s'", checksum)
458-
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", message)
459-
conditions.MarkReconciling(obj, "NewRevision", message)
488+
if obj.GetArtifact() != nil {
489+
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", message)
490+
}
491+
rreconcile.ProgressiveStatus(true, obj, meta.ProgressingReason, "building artifact: %s", message)
492+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
493+
ctrl.LoggerFrom(ctx).Error(err, "failed to patch")
494+
return sreconcile.ResultEmpty, err
495+
}
460496
}
461497

462498
// Create potential new artifact.
@@ -482,13 +518,13 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
482518
// early.
483519
// On a successful archive, the Artifact in the Status of the object is set,
484520
// and the symlink in the Storage is updated to its path.
485-
func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) {
521+
func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) {
486522
// Set the ArtifactInStorageCondition if there's no drift.
487523
defer func() {
488524
if obj.GetArtifact().HasRevision(artifact.Revision) {
489525
conditions.Delete(obj, sourcev1.ArtifactOutdatedCondition)
490526
conditions.MarkTrue(obj, sourcev1.ArtifactInStorageCondition, meta.SucceededReason,
491-
"stored artifact for revision '%s'", artifact.Revision)
527+
"stored artifact: revision '%s'", artifact.Revision)
492528
}
493529

494530
chartRepo.Unload()

0 commit comments

Comments
 (0)