Skip to content

Commit 55573f5

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

File tree

2 files changed

+181
-60
lines changed

2 files changed

+181
-60
lines changed

controllers/ocirepository_controller.go

+57-19
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import (
3131
"time"
3232

3333
"github.com/Masterminds/semver/v3"
34-
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
3534
soci "github.com/fluxcd/source-controller/internal/oci"
3635
"github.com/google/go-containerregistry/pkg/authn"
3736
"github.com/google/go-containerregistry/pkg/authn/k8schain"
@@ -54,16 +53,19 @@ import (
5453
"sigs.k8s.io/controller-runtime/pkg/predicate"
5554
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
5655

56+
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
5757
"github.com/fluxcd/pkg/apis/meta"
5858
"github.com/fluxcd/pkg/oci"
5959
"github.com/fluxcd/pkg/oci/auth/login"
6060
"github.com/fluxcd/pkg/runtime/conditions"
6161
helper "github.com/fluxcd/pkg/runtime/controller"
6262
"github.com/fluxcd/pkg/runtime/patch"
6363
"github.com/fluxcd/pkg/runtime/predicates"
64+
rreconcile "github.com/fluxcd/pkg/runtime/reconcile"
6465
"github.com/fluxcd/pkg/sourceignore"
6566
"github.com/fluxcd/pkg/untar"
6667
"github.com/fluxcd/pkg/version"
68+
6769
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
6870
serror "github.com/fluxcd/source-controller/internal/error"
6971
sreconcile "github.com/fluxcd/source-controller/internal/reconcile"
@@ -120,7 +122,7 @@ func (e invalidOCIURLError) Error() string {
120122
// ociRepositoryReconcileFunc is the function type for all the v1beta2.OCIRepository
121123
// (sub)reconcile functions. The type implementations are grouped and
122124
// executed serially to perform the complete reconcile of the object.
123-
type ociRepositoryReconcileFunc func(ctx context.Context, obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error)
125+
type ociRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error)
124126

125127
// OCIRepositoryReconciler reconciles a v1beta2.OCIRepository object
126128
type OCIRepositoryReconciler struct {
@@ -131,6 +133,8 @@ type OCIRepositoryReconciler struct {
131133
Storage *Storage
132134
ControllerName string
133135
requeueDependency time.Duration
136+
137+
patchOptions []patch.Option
134138
}
135139

136140
type OCIRepositoryReconcilerOptions struct {
@@ -145,6 +149,8 @@ func (r *OCIRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error {
145149
}
146150

147151
func (r *OCIRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts OCIRepositoryReconcilerOptions) error {
152+
r.patchOptions = getPatchOptions(ociRepositoryReadyCondition.Owned, r.ControllerName)
153+
148154
r.requeueDependency = opts.DependencyRequeueInterval
149155

150156
return ctrl.NewControllerManagedBy(mgr).
@@ -178,18 +184,15 @@ func (r *OCIRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reques
178184
r.RecordSuspend(ctx, obj, obj.Spec.Suspend)
179185

180186
// Initialize the patch helper with the current version of the object.
181-
patchHelper, err := patch.NewHelper(obj, r.Client)
182-
if err != nil {
183-
return ctrl.Result{}, err
184-
}
187+
serialPatcher := patch.NewSerialPatcher(obj, r.Client)
185188

186189
// recResult stores the abstracted reconcile result.
187190
var recResult sreconcile.Result
188191

189192
// Always attempt to patch the object and status after each reconciliation
190193
// NOTE: The final runtime result and error are set in this block.
191194
defer func() {
192-
summarizeHelper := summarize.NewHelper(r.EventRecorder, patchHelper)
195+
summarizeHelper := summarize.NewHelper(r.EventRecorder, serialPatcher)
193196
summarizeOpts := []summarize.Option{
194197
summarize.WithConditions(ociRepositoryReadyCondition),
195198
summarize.WithBiPolarityConditionTypes(sourcev1.SourceVerifiedCondition),
@@ -236,19 +239,36 @@ func (r *OCIRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reques
236239
r.reconcileSource,
237240
r.reconcileArtifact,
238241
}
239-
recResult, retErr = r.reconcile(ctx, obj, reconcilers)
242+
recResult, retErr = r.reconcile(ctx, serialPatcher, obj, reconcilers)
240243
return
241244
}
242245

243246
// reconcile iterates through the ociRepositoryReconcileFunc tasks for the
244247
// object. It returns early on the first call that returns
245248
// reconcile.ResultRequeue, or produces an error.
246-
func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.OCIRepository, reconcilers []ociRepositoryReconcileFunc) (sreconcile.Result, error) {
249+
func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.OCIRepository, reconcilers []ociRepositoryReconcileFunc) (sreconcile.Result, error) {
247250
oldObj := obj.DeepCopy()
248251

249-
// Mark as reconciling if generation differs.
250-
if obj.Generation != obj.Status.ObservedGeneration {
251-
conditions.MarkReconciling(obj, "NewGeneration", "reconciling new object generation (%d)", obj.Generation)
252+
rreconcile.ProgressiveStatus(false, obj, meta.ProgressingReason, "reconciliation in progress")
253+
254+
var reconcileAtVal string
255+
if v, ok := meta.ReconcileAnnotationValue(obj.GetAnnotations()); ok {
256+
reconcileAtVal = v
257+
}
258+
259+
// Persist reconciling status if generation differs or reconciliation is
260+
// requested.
261+
switch {
262+
case obj.Generation != obj.Status.ObservedGeneration:
263+
rreconcile.ProgressiveStatus(false, obj, meta.ProgressingReason,
264+
"processing object: new generation %d -> %d", obj.Status.ObservedGeneration, obj.Generation)
265+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
266+
return sreconcile.ResultEmpty, err
267+
}
268+
case reconcileAtVal != obj.Status.GetLastHandledReconcileRequest():
269+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
270+
return sreconcile.ResultEmpty, err
271+
}
252272
}
253273

254274
// Create temp working dir
@@ -276,7 +296,7 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.O
276296

277297
// Run the sub-reconcilers and build the result of reconciliation.
278298
for _, rec := range reconcilers {
279-
recResult, err := rec(ctx, obj, &metadata, tmpDir)
299+
recResult, err := rec(ctx, sp, obj, &metadata, tmpDir)
280300
// Exit immediately on ResultRequeue.
281301
if recResult == sreconcile.ResultRequeue {
282302
return sreconcile.ResultRequeue, nil
@@ -299,7 +319,8 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.O
299319

300320
// reconcileSource fetches the upstream OCI artifact metadata and content.
301321
// If this fails, it records v1beta2.FetchFailedCondition=True on the object and returns early.
302-
func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) {
322+
func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher,
323+
obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) {
303324
var auth authn.Authenticator
304325

305326
ctxTimeout, cancel := context.WithTimeout(ctx, obj.Spec.Timeout.Duration)
@@ -385,8 +406,14 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
385406
defer func() {
386407
if !obj.GetArtifact().HasRevision(revision) {
387408
message := fmt.Sprintf("new revision '%s' for '%s'", revision, url)
388-
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", message)
389-
conditions.MarkReconciling(obj, "NewRevision", message)
409+
if obj.GetArtifact() != nil {
410+
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", message)
411+
}
412+
rreconcile.ProgressiveStatus(true, obj, meta.ProgressingReason, "building artifact: %s", message)
413+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
414+
ctrl.LoggerFrom(ctx).Error(err, "failed to patch")
415+
return
416+
}
390417
}
391418
}()
392419

@@ -876,22 +903,32 @@ func oidcAuth(ctx context.Context, url, provider string) (authn.Authenticator, e
876903
// condition is added.
877904
// The hostname of any URL in the Status of the object are updated, to ensure
878905
// they match the Storage server hostname of current runtime.
879-
func (r *OCIRepositoryReconciler) reconcileStorage(ctx context.Context, obj *sourcev1.OCIRepository, _ *sourcev1.Artifact, _ string) (sreconcile.Result, error) {
906+
func (r *OCIRepositoryReconciler) reconcileStorage(ctx context.Context, sp *patch.SerialPatcher,
907+
obj *sourcev1.OCIRepository, _ *sourcev1.Artifact, _ string) (sreconcile.Result, error) {
880908
// Garbage collect previous advertised artifact(s) from storage
881909
_ = r.garbageCollect(ctx, obj)
882910

883911
// Determine if the advertised artifact is still in storage
912+
var artifactMissing bool
884913
if artifact := obj.GetArtifact(); artifact != nil && !r.Storage.ArtifactExist(*artifact) {
885914
obj.Status.Artifact = nil
886915
obj.Status.URL = ""
916+
artifactMissing = true
887917
// Remove the condition as the artifact doesn't exist.
888918
conditions.Delete(obj, sourcev1.ArtifactInStorageCondition)
889919
}
890920

891921
// Record that we do not have an artifact
892922
if obj.GetArtifact() == nil {
893-
conditions.MarkReconciling(obj, "NoArtifact", "no artifact for resource in storage")
923+
msg := "building artifact"
924+
if artifactMissing {
925+
msg += ": disappeared from storage"
926+
}
927+
rreconcile.ProgressiveStatus(true, obj, meta.ProgressingReason, msg)
894928
conditions.Delete(obj, sourcev1.ArtifactInStorageCondition)
929+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
930+
return sreconcile.ResultEmpty, err
931+
}
895932
return sreconcile.ResultSuccess, nil
896933
}
897934

@@ -911,7 +948,8 @@ func (r *OCIRepositoryReconciler) reconcileStorage(ctx context.Context, obj *sou
911948
// early.
912949
// On a successful archive, the Artifact in the Status of the object is set,
913950
// and the symlink in the Storage is updated to its path.
914-
func (r *OCIRepositoryReconciler) reconcileArtifact(ctx context.Context, obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) {
951+
func (r *OCIRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *patch.SerialPatcher,
952+
obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) {
915953
revision := metadata.Revision
916954

917955
// Create artifact

0 commit comments

Comments
 (0)