Skip to content

Commit 887b530

Browse files
committed
Add progressive status in gitrepository reconciler
Signed-off-by: Sunny <[email protected]>
1 parent e253e4c commit 887b530

File tree

2 files changed

+248
-74
lines changed

2 files changed

+248
-74
lines changed

controllers/gitrepository_controller.go

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import (
5050
helper "github.com/fluxcd/pkg/runtime/controller"
5151
"github.com/fluxcd/pkg/runtime/patch"
5252
"github.com/fluxcd/pkg/runtime/predicates"
53+
rreconcile "github.com/fluxcd/pkg/runtime/reconcile"
5354

5455
"github.com/fluxcd/pkg/sourceignore"
5556
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
@@ -102,6 +103,15 @@ var gitRepositoryFailConditions = []string{
102103
sourcev1.StorageOperationFailedCondition,
103104
}
104105

106+
// getPatchOptions composes patch options based on the given parameters.
107+
// It is used as the options used when patching an object.
108+
func getPatchOptions(ownedConditions []string, controllerName string) []patch.Option {
109+
return []patch.Option{
110+
patch.WithOwnedConditions{Conditions: ownedConditions},
111+
patch.WithFieldOwner(controllerName),
112+
}
113+
}
114+
105115
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories,verbs=get;list;watch;create;update;patch;delete
106116
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories/status,verbs=get;update;patch
107117
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories/finalizers,verbs=get;create;update;patch;delete
@@ -118,6 +128,8 @@ type GitRepositoryReconciler struct {
118128

119129
requeueDependency time.Duration
120130
features map[string]bool
131+
132+
patchOptions []patch.Option
121133
}
122134

123135
type GitRepositoryReconcilerOptions struct {
@@ -128,13 +140,15 @@ type GitRepositoryReconcilerOptions struct {
128140

129141
// gitRepositoryReconcileFunc is the function type for all the
130142
// v1beta2.GitRepository (sub)reconcile functions.
131-
type gitRepositoryReconcileFunc func(ctx context.Context, obj *sourcev1.GitRepository, commit *git.Commit, includes *artifactSet, dir string) (sreconcile.Result, error)
143+
type gitRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.GitRepository, commit *git.Commit, includes *artifactSet, dir string) (sreconcile.Result, error)
132144

133145
func (r *GitRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error {
134146
return r.SetupWithManagerAndOptions(mgr, GitRepositoryReconcilerOptions{})
135147
}
136148

137149
func (r *GitRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, opts GitRepositoryReconcilerOptions) error {
150+
r.patchOptions = getPatchOptions(gitRepositoryReadyCondition.Owned, r.ControllerName)
151+
138152
r.requeueDependency = opts.DependencyRequeueInterval
139153

140154
if r.features == nil {
@@ -167,18 +181,15 @@ func (r *GitRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reques
167181
r.RecordSuspend(ctx, obj, obj.Spec.Suspend)
168182

169183
// Initialize the patch helper with the current version of the object.
170-
patchHelper, err := patch.NewHelper(obj, r.Client)
171-
if err != nil {
172-
return ctrl.Result{}, err
173-
}
184+
serialPatcher := patch.NewSerialPatcher(obj, r.Client)
174185

175186
// recResult stores the abstracted reconcile result.
176187
var recResult sreconcile.Result
177188

178189
// Always attempt to patch the object and status after each reconciliation
179190
// NOTE: The final runtime result and error are set in this block.
180191
defer func() {
181-
summarizeHelper := summarize.NewHelper(r.EventRecorder, patchHelper)
192+
summarizeHelper := summarize.NewHelper(r.EventRecorder, serialPatcher)
182193
summarizeOpts := []summarize.Option{
183194
summarize.WithConditions(gitRepositoryReadyCondition),
184195
summarize.WithBiPolarityConditionTypes(sourcev1.SourceVerifiedCondition),
@@ -227,19 +238,36 @@ func (r *GitRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reques
227238
r.reconcileInclude,
228239
r.reconcileArtifact,
229240
}
230-
recResult, retErr = r.reconcile(ctx, obj, reconcilers)
241+
recResult, retErr = r.reconcile(ctx, serialPatcher, obj, reconcilers)
231242
return
232243
}
233244

234245
// reconcile iterates through the gitRepositoryReconcileFunc tasks for the
235246
// object. It returns early on the first call that returns
236247
// reconcile.ResultRequeue, or produces an error.
237-
func (r *GitRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.GitRepository, reconcilers []gitRepositoryReconcileFunc) (sreconcile.Result, error) {
248+
func (r *GitRepositoryReconciler) reconcile(ctx context.Context, sp *patch.SerialPatcher,
249+
obj *sourcev1.GitRepository, reconcilers []gitRepositoryReconcileFunc) (sreconcile.Result, error) {
238250
oldObj := obj.DeepCopy()
239251

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

245273
// Create temp dir for Git clone
@@ -268,7 +296,7 @@ func (r *GitRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.G
268296
resErr error
269297
)
270298
for _, rec := range reconcilers {
271-
recResult, err := rec(ctx, obj, &commit, &includes, tmpDir)
299+
recResult, err := rec(ctx, sp, obj, &commit, &includes, tmpDir)
272300
// Exit immediately on ResultRequeue.
273301
if recResult == sreconcile.ResultRequeue {
274302
return sreconcile.ResultRequeue, nil
@@ -359,23 +387,32 @@ func (r *GitRepositoryReconciler) shouldNotify(oldObj, newObj *sourcev1.GitRepos
359387
// condition is added.
360388
// The hostname of any URL in the Status of the object are updated, to ensure
361389
// they match the Storage server hostname of current runtime.
362-
func (r *GitRepositoryReconciler) reconcileStorage(ctx context.Context,
390+
func (r *GitRepositoryReconciler) reconcileStorage(ctx context.Context, sp *patch.SerialPatcher,
363391
obj *sourcev1.GitRepository, _ *git.Commit, _ *artifactSet, _ string) (sreconcile.Result, error) {
364392
// Garbage collect previous advertised artifact(s) from storage
365393
_ = r.garbageCollect(ctx, obj)
366394

367395
// Determine if the advertised artifact is still in storage
396+
var artifactMissing bool
368397
if artifact := obj.GetArtifact(); artifact != nil && !r.Storage.ArtifactExist(*artifact) {
369398
obj.Status.Artifact = nil
370399
obj.Status.URL = ""
400+
artifactMissing = true
371401
// Remove the condition as the artifact doesn't exist.
372402
conditions.Delete(obj, sourcev1.ArtifactInStorageCondition)
373403
}
374404

375405
// Record that we do not have an artifact
376406
if obj.GetArtifact() == nil {
377-
conditions.MarkReconciling(obj, "NoArtifact", "no artifact for resource in storage")
407+
msg := "building artifact"
408+
if artifactMissing {
409+
msg += ": disappeared from storage"
410+
}
411+
rreconcile.ProgressiveStatus(true, obj, meta.ProgressingReason, msg)
378412
conditions.Delete(obj, sourcev1.ArtifactInStorageCondition)
413+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
414+
return sreconcile.ResultEmpty, err
415+
}
379416
return sreconcile.ResultSuccess, nil
380417
}
381418

@@ -417,7 +454,7 @@ func (r *GitRepositoryReconciler) reconcileStorage(ctx context.Context,
417454
// and the local artifact are on the same revision, and no other source content
418455
// related configurations have changed since last reconciliation. If there's a
419456
// change, it short-circuits the whole reconciliation with an early return.
420-
func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
457+
func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher,
421458
obj *sourcev1.GitRepository, commit *git.Commit, includes *artifactSet, dir string) (sreconcile.Result, error) {
422459
// Remove previously failed source verification status conditions. The
423460
// failing verification should be recalculated. But an existing successful
@@ -477,9 +514,15 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
477514
// Observe if the artifacts still match the previous included ones
478515
if artifacts.Diff(obj.Status.IncludedArtifacts) {
479516
message := fmt.Sprintf("included artifacts differ from last observed includes")
480-
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "IncludeChange", message)
481-
conditions.MarkReconciling(obj, "IncludeChange", message)
517+
if obj.Status.IncludedArtifacts != nil {
518+
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "IncludeChange", message)
519+
}
520+
rreconcile.ProgressiveStatus(true, obj, meta.ProgressingReason, "building artifact: %s", message)
521+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
522+
return sreconcile.ResultEmpty, err
523+
}
482524
}
525+
conditions.Delete(obj, sourcev1.ArtifactOutdatedCondition)
483526

484527
// Persist the ArtifactSet.
485528
*includes = *artifacts
@@ -540,8 +583,13 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
540583
// Mark observations about the revision on the object
541584
if !obj.GetArtifact().HasRevision(commit.String()) {
542585
message := fmt.Sprintf("new upstream revision '%s'", commit.String())
543-
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", message)
544-
conditions.MarkReconciling(obj, "NewRevision", message)
586+
if obj.GetArtifact() != nil {
587+
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", message)
588+
}
589+
rreconcile.ProgressiveStatus(true, obj, meta.ProgressingReason, "building artifact: %s", message)
590+
if err := sp.Patch(ctx, obj, r.patchOptions...); err != nil {
591+
return sreconcile.ResultEmpty, err
592+
}
545593
}
546594
return sreconcile.ResultSuccess, nil
547595
}
@@ -558,7 +606,7 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
558606
// On a successful archive, the Artifact, Includes, observed ignore, recurse
559607
// submodules and observed include in the Status of the object are set, and the
560608
// symlink in the Storage is updated to its path.
561-
func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context,
609+
func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *patch.SerialPatcher,
562610
obj *sourcev1.GitRepository, commit *git.Commit, includes *artifactSet, dir string) (sreconcile.Result, error) {
563611

564612
// Create potential new artifact with current available metadata
@@ -672,7 +720,7 @@ func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context,
672720
// v1beta2.IncludeUnavailableCondition from the object.
673721
// When the composed artifactSet differs from the current set in the Status of
674722
// the object, it marks the object with v1beta2.ArtifactOutdatedCondition=True.
675-
func (r *GitRepositoryReconciler) reconcileInclude(ctx context.Context,
723+
func (r *GitRepositoryReconciler) reconcileInclude(ctx context.Context, sp *patch.SerialPatcher,
676724
obj *sourcev1.GitRepository, _ *git.Commit, includes *artifactSet, dir string) (sreconcile.Result, error) {
677725

678726
for i, incl := range obj.Spec.Include {

0 commit comments

Comments
 (0)