@@ -50,6 +50,7 @@ import (
50
50
helper "github.com/fluxcd/pkg/runtime/controller"
51
51
"github.com/fluxcd/pkg/runtime/patch"
52
52
"github.com/fluxcd/pkg/runtime/predicates"
53
+ rreconcile "github.com/fluxcd/pkg/runtime/reconcile"
53
54
54
55
"github.com/fluxcd/pkg/sourceignore"
55
56
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
@@ -102,6 +103,15 @@ var gitRepositoryFailConditions = []string{
102
103
sourcev1 .StorageOperationFailedCondition ,
103
104
}
104
105
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
+
105
115
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories,verbs=get;list;watch;create;update;patch;delete
106
116
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories/status,verbs=get;update;patch
107
117
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories/finalizers,verbs=get;create;update;patch;delete
@@ -118,6 +128,8 @@ type GitRepositoryReconciler struct {
118
128
119
129
requeueDependency time.Duration
120
130
features map [string ]bool
131
+
132
+ patchOptions []patch.Option
121
133
}
122
134
123
135
type GitRepositoryReconcilerOptions struct {
@@ -128,13 +140,15 @@ type GitRepositoryReconcilerOptions struct {
128
140
129
141
// gitRepositoryReconcileFunc is the function type for all the
130
142
// 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 )
132
144
133
145
func (r * GitRepositoryReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
134
146
return r .SetupWithManagerAndOptions (mgr , GitRepositoryReconcilerOptions {})
135
147
}
136
148
137
149
func (r * GitRepositoryReconciler ) SetupWithManagerAndOptions (mgr ctrl.Manager , opts GitRepositoryReconcilerOptions ) error {
150
+ r .patchOptions = getPatchOptions (gitRepositoryReadyCondition .Owned , r .ControllerName )
151
+
138
152
r .requeueDependency = opts .DependencyRequeueInterval
139
153
140
154
if r .features == nil {
@@ -167,18 +181,15 @@ func (r *GitRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reques
167
181
r .RecordSuspend (ctx , obj , obj .Spec .Suspend )
168
182
169
183
// 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 )
174
185
175
186
// recResult stores the abstracted reconcile result.
176
187
var recResult sreconcile.Result
177
188
178
189
// Always attempt to patch the object and status after each reconciliation
179
190
// NOTE: The final runtime result and error are set in this block.
180
191
defer func () {
181
- summarizeHelper := summarize .NewHelper (r .EventRecorder , patchHelper )
192
+ summarizeHelper := summarize .NewHelper (r .EventRecorder , serialPatcher )
182
193
summarizeOpts := []summarize.Option {
183
194
summarize .WithConditions (gitRepositoryReadyCondition ),
184
195
summarize .WithBiPolarityConditionTypes (sourcev1 .SourceVerifiedCondition ),
@@ -227,19 +238,36 @@ func (r *GitRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reques
227
238
r .reconcileInclude ,
228
239
r .reconcileArtifact ,
229
240
}
230
- recResult , retErr = r .reconcile (ctx , obj , reconcilers )
241
+ recResult , retErr = r .reconcile (ctx , serialPatcher , obj , reconcilers )
231
242
return
232
243
}
233
244
234
245
// reconcile iterates through the gitRepositoryReconcileFunc tasks for the
235
246
// object. It returns early on the first call that returns
236
247
// 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 ) {
238
250
oldObj := obj .DeepCopy ()
239
251
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
+ }
243
271
}
244
272
245
273
// Create temp dir for Git clone
@@ -268,7 +296,7 @@ func (r *GitRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.G
268
296
resErr error
269
297
)
270
298
for _ , rec := range reconcilers {
271
- recResult , err := rec (ctx , obj , & commit , & includes , tmpDir )
299
+ recResult , err := rec (ctx , sp , obj , & commit , & includes , tmpDir )
272
300
// Exit immediately on ResultRequeue.
273
301
if recResult == sreconcile .ResultRequeue {
274
302
return sreconcile .ResultRequeue , nil
@@ -359,23 +387,32 @@ func (r *GitRepositoryReconciler) shouldNotify(oldObj, newObj *sourcev1.GitRepos
359
387
// condition is added.
360
388
// The hostname of any URL in the Status of the object are updated, to ensure
361
389
// 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 ,
363
391
obj * sourcev1.GitRepository , _ * git.Commit , _ * artifactSet , _ string ) (sreconcile.Result , error ) {
364
392
// Garbage collect previous advertised artifact(s) from storage
365
393
_ = r .garbageCollect (ctx , obj )
366
394
367
395
// Determine if the advertised artifact is still in storage
396
+ var artifactMissing bool
368
397
if artifact := obj .GetArtifact (); artifact != nil && ! r .Storage .ArtifactExist (* artifact ) {
369
398
obj .Status .Artifact = nil
370
399
obj .Status .URL = ""
400
+ artifactMissing = true
371
401
// Remove the condition as the artifact doesn't exist.
372
402
conditions .Delete (obj , sourcev1 .ArtifactInStorageCondition )
373
403
}
374
404
375
405
// Record that we do not have an artifact
376
406
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 )
378
412
conditions .Delete (obj , sourcev1 .ArtifactInStorageCondition )
413
+ if err := sp .Patch (ctx , obj , r .patchOptions ... ); err != nil {
414
+ return sreconcile .ResultEmpty , err
415
+ }
379
416
return sreconcile .ResultSuccess , nil
380
417
}
381
418
@@ -417,7 +454,7 @@ func (r *GitRepositoryReconciler) reconcileStorage(ctx context.Context,
417
454
// and the local artifact are on the same revision, and no other source content
418
455
// related configurations have changed since last reconciliation. If there's a
419
456
// 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 ,
421
458
obj * sourcev1.GitRepository , commit * git.Commit , includes * artifactSet , dir string ) (sreconcile.Result , error ) {
422
459
// Remove previously failed source verification status conditions. The
423
460
// failing verification should be recalculated. But an existing successful
@@ -477,9 +514,15 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
477
514
// Observe if the artifacts still match the previous included ones
478
515
if artifacts .Diff (obj .Status .IncludedArtifacts ) {
479
516
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
+ }
482
524
}
525
+ conditions .Delete (obj , sourcev1 .ArtifactOutdatedCondition )
483
526
484
527
// Persist the ArtifactSet.
485
528
* includes = * artifacts
@@ -540,8 +583,13 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
540
583
// Mark observations about the revision on the object
541
584
if ! obj .GetArtifact ().HasRevision (commit .String ()) {
542
585
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
+ }
545
593
}
546
594
return sreconcile .ResultSuccess , nil
547
595
}
@@ -558,7 +606,7 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
558
606
// On a successful archive, the Artifact, Includes, observed ignore, recurse
559
607
// submodules and observed include in the Status of the object are set, and the
560
608
// 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 ,
562
610
obj * sourcev1.GitRepository , commit * git.Commit , includes * artifactSet , dir string ) (sreconcile.Result , error ) {
563
611
564
612
// Create potential new artifact with current available metadata
@@ -672,7 +720,7 @@ func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context,
672
720
// v1beta2.IncludeUnavailableCondition from the object.
673
721
// When the composed artifactSet differs from the current set in the Status of
674
722
// 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 ,
676
724
obj * sourcev1.GitRepository , _ * git.Commit , includes * artifactSet , dir string ) (sreconcile.Result , error ) {
677
725
678
726
for i , incl := range obj .Spec .Include {
0 commit comments