Skip to content

Commit 9c866ee

Browse files
committed
Add progressive status in helmchart reconciler
Signed-off-by: Sunny <darkowlzz@protonmail.com>
1 parent 3d6a5e1 commit 9c866ee

File tree

2 files changed

+244
-49
lines changed

2 files changed

+244
-49
lines changed

controllers/helmchart_controller.go

+54-21
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import (
3030

3131
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
3232
soci "github.com/fluxcd/source-controller/internal/oci"
33+
"github.com/google/go-containerregistry/pkg/authn"
34+
"github.com/google/go-containerregistry/pkg/v1/remote"
3335
helmgetter "helm.sh/helm/v3/pkg/getter"
3436
helmreg "helm.sh/helm/v3/pkg/registry"
3537
corev1 "k8s.io/api/core/v1"
@@ -56,9 +58,8 @@ import (
5658
helper "github.com/fluxcd/pkg/runtime/controller"
5759
"github.com/fluxcd/pkg/runtime/patch"
5860
"github.com/fluxcd/pkg/runtime/predicates"
61+
rreconcile "github.com/fluxcd/pkg/runtime/reconcile"
5962
"github.com/fluxcd/pkg/untar"
60-
"github.com/google/go-containerregistry/pkg/authn"
61-
"github.com/google/go-containerregistry/pkg/v1/remote"
6263

6364
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
6465
"github.com/fluxcd/source-controller/internal/cache"
@@ -133,6 +134,8 @@ type HelmChartReconciler struct {
133134
Cache *cache.Cache
134135
TTL time.Duration
135136
*cache.CacheRecorder
137+
138+
patchOptions []patch.Option
136139
}
137140

138141
func (r *HelmChartReconciler) SetupWithManager(mgr ctrl.Manager) error {
@@ -147,9 +150,11 @@ type HelmChartReconcilerOptions struct {
147150
// helmChartReconcileFunc is the function type for all the v1beta2.HelmChart
148151
// (sub)reconcile functions. The type implementations are grouped and
149152
// executed serially to perform the complete reconcile of the object.
150-
type helmChartReconcileFunc func(ctx context.Context, obj *sourcev1.HelmChart, build *chart.Build) (sreconcile.Result, error)
153+
type helmChartReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmChart, build *chart.Build) (sreconcile.Result, error)
151154

152155
func (r *HelmChartReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts HelmChartReconcilerOptions) error {
156+
r.patchOptions = getPatchOptions(helmChartReadyCondition.Owned, r.ControllerName)
157+
153158
if err := mgr.GetCache().IndexField(context.TODO(), &sourcev1.HelmRepository{}, sourcev1.HelmRepositoryURLIndexKey,
154159
r.indexHelmRepositoryByURL); err != nil {
155160
return fmt.Errorf("failed setting index fields: %w", err)
@@ -200,18 +205,15 @@ func (r *HelmChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
200205
r.RecordSuspend(ctx, obj, obj.Spec.Suspend)
201206

202207
// Initialize the patch helper with the current version of the object.
203-
patchHelper, err := patch.NewHelper(obj, r.Client)
204-
if err != nil {
205-
return ctrl.Result{}, err
206-
}
208+
serialPatcher := patch.NewSerialPatcher(obj, r.Client)
207209

208210
// recResult stores the abstracted reconcile result.
209211
var recResult sreconcile.Result
210212

211213
// Always attempt to patch the object after each reconciliation.
212214
// NOTE: The final runtime result and error are set in this block.
213215
defer func() {
214-
summarizeHelper := summarize.NewHelper(r.EventRecorder, patchHelper)
216+
summarizeHelper := summarize.NewHelper(r.EventRecorder, serialPatcher)
215217
summarizeOpts := []summarize.Option{
216218
summarize.WithConditions(helmChartReadyCondition),
217219
summarize.WithBiPolarityConditionTypes(sourcev1.SourceVerifiedCondition),
@@ -259,19 +261,35 @@ func (r *HelmChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
259261
r.reconcileSource,
260262
r.reconcileArtifact,
261263
}
262-
recResult, retErr = r.reconcile(ctx, obj, reconcilers)
264+
recResult, retErr = r.reconcile(ctx, serialPatcher, obj, reconcilers)
263265
return
264266
}
265267

266268
// reconcile iterates through the helmChartReconcileFunc tasks for the
267269
// object. It returns early on the first call that returns
268270
// reconcile.ResultRequeue, or produces an error.
269-
func (r *HelmChartReconciler) reconcile(ctx context.Context, obj *sourcev1.HelmChart, reconcilers []helmChartReconcileFunc) (sreconcile.Result, error) {
271+
func (r *HelmChartReconciler) reconcile(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmChart, reconcilers []helmChartReconcileFunc) (sreconcile.Result, error) {
270272
oldObj := obj.DeepCopy()
271273

272-
// Mark as reconciling if generation differs.
273-
if obj.Generation != obj.Status.ObservedGeneration {
274-
conditions.MarkReconciling(obj, "NewGeneration", "reconciling new object generation (%d)", obj.Generation)
274+
rreconcile.ProgressiveStatus(false, obj, meta.ProgressingReason, "reconciliation in progress")
275+
276+
var reconcileAtVal string
277+
if v, ok := meta.ReconcileAnnotationValue(obj.GetAnnotations()); ok {
278+
reconcileAtVal = v
279+
}
280+
281+
// Persist reconciling if generation differs or reconciliation is requested.
282+
switch {
283+
case obj.Generation != obj.Status.ObservedGeneration:
284+
rreconcile.ProgressiveStatus(false, obj, meta.ProgressingReason,
285+
"processing object: new generation %d -> %d", obj.Status.ObservedGeneration, obj.Generation)
286+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
287+
return sreconcile.ResultEmpty, err
288+
}
289+
case reconcileAtVal != obj.Status.GetLastHandledReconcileRequest():
290+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
291+
return sreconcile.ResultEmpty, err
292+
}
275293
}
276294

277295
// Run the sub-reconcilers and build the result of reconciliation.
@@ -281,7 +299,7 @@ func (r *HelmChartReconciler) reconcile(ctx context.Context, obj *sourcev1.HelmC
281299
resErr error
282300
)
283301
for _, rec := range reconcilers {
284-
recResult, err := rec(ctx, obj, &build)
302+
recResult, err := rec(ctx, sp, obj, &build)
285303
// Exit immediately on ResultRequeue.
286304
if recResult == sreconcile.ResultRequeue {
287305
return sreconcile.ResultRequeue, nil
@@ -344,22 +362,31 @@ func (r *HelmChartReconciler) notify(ctx context.Context, oldObj, newObj *source
344362
// condition is added.
345363
// The hostname of any URL in the Status of the object are updated, to ensure
346364
// they match the Storage server hostname of current runtime.
347-
func (r *HelmChartReconciler) reconcileStorage(ctx context.Context, obj *sourcev1.HelmChart, build *chart.Build) (sreconcile.Result, error) {
365+
func (r *HelmChartReconciler) reconcileStorage(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmChart, build *chart.Build) (sreconcile.Result, error) {
348366
// Garbage collect previous advertised artifact(s) from storage
349367
_ = r.garbageCollect(ctx, obj)
350368

351369
// Determine if the advertised artifact is still in storage
370+
var artifactMissing bool
352371
if artifact := obj.GetArtifact(); artifact != nil && !r.Storage.ArtifactExist(*artifact) {
353372
obj.Status.Artifact = nil
354373
obj.Status.URL = ""
374+
artifactMissing = true
355375
// Remove the condition as the artifact doesn't exist.
356376
conditions.Delete(obj, sourcev1.ArtifactInStorageCondition)
357377
}
358378

359379
// Record that we do not have an artifact
360380
if obj.GetArtifact() == nil {
361-
conditions.MarkReconciling(obj, "NoArtifact", "no artifact for resource in storage")
381+
msg := "building artifact"
382+
if artifactMissing {
383+
msg += ": disappeared from storage"
384+
}
385+
rreconcile.ProgressiveStatus(true, obj, meta.ProgressingReason, msg)
362386
conditions.Delete(obj, sourcev1.ArtifactInStorageCondition)
387+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
388+
return sreconcile.ResultEmpty, err
389+
}
363390
return sreconcile.ResultSuccess, nil
364391
}
365392

@@ -371,7 +398,7 @@ func (r *HelmChartReconciler) reconcileStorage(ctx context.Context, obj *sourcev
371398
return sreconcile.ResultSuccess, nil
372399
}
373400

374-
func (r *HelmChartReconciler) reconcileSource(ctx context.Context, obj *sourcev1.HelmChart, build *chart.Build) (_ sreconcile.Result, retErr error) {
401+
func (r *HelmChartReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmChart, build *chart.Build) (_ sreconcile.Result, retErr error) {
375402
// Remove any failed verification condition.
376403
// The reason is that a failing verification should be recalculated.
377404
if conditions.IsFalse(obj, sourcev1.SourceVerifiedCondition) {
@@ -418,7 +445,7 @@ func (r *HelmChartReconciler) reconcileSource(ctx context.Context, obj *sourcev1
418445
// Defer observation of build result
419446
defer func() {
420447
// Record both success and error observations on the object
421-
observeChartBuild(obj, build, retErr)
448+
observeChartBuild(ctx, sp, r.patchOptions, obj, build, retErr)
422449

423450
// If we actually build a chart, take a historical note of any dependencies we resolved.
424451
// The reason this is a done conditionally, is because if we have a cached one in storage,
@@ -810,7 +837,7 @@ func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj
810837
// early.
811838
// On a successful archive, the Artifact in the Status of the object is set,
812839
// and the symlink in the Storage is updated to its path.
813-
func (r *HelmChartReconciler) reconcileArtifact(ctx context.Context, obj *sourcev1.HelmChart, b *chart.Build) (sreconcile.Result, error) {
840+
func (r *HelmChartReconciler) reconcileArtifact(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmChart, b *chart.Build) (sreconcile.Result, error) {
814841
// Without a complete chart build, there is little to reconcile
815842
if !b.Complete() {
816843
return sreconcile.ResultRequeue, nil
@@ -1265,10 +1292,16 @@ func (r *HelmChartReconciler) eventLogf(ctx context.Context, obj runtime.Object,
12651292
}
12661293

12671294
// observeChartBuild records the observation on the given given build and error on the object.
1268-
func observeChartBuild(obj *sourcev1.HelmChart, build *chart.Build, err error) {
1295+
func observeChartBuild(ctx context.Context, sp *patch.SerialPatcher, pOpts []patch.Option, obj *sourcev1.HelmChart, build *chart.Build, err error) {
12691296
if build.HasMetadata() {
12701297
if build.Name != obj.Status.ObservedChartName || !obj.GetArtifact().HasRevision(build.Version) {
1271-
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewChart", build.Summary())
1298+
if obj.GetArtifact() != nil {
1299+
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewChart", build.Summary())
1300+
}
1301+
rreconcile.ProgressiveStatus(true, obj, meta.ProgressingReason, "building artifact: %s", build.Summary())
1302+
if err := sp.Patch(ctx, obj, pOpts...); err != nil {
1303+
ctrl.LoggerFrom(ctx).Error(err, "failed to patch")
1304+
}
12721305
}
12731306
}
12741307

0 commit comments

Comments
 (0)