@@ -31,7 +31,6 @@ import (
31
31
"time"
32
32
33
33
"github.com/Masterminds/semver/v3"
34
- eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
35
34
soci "github.com/fluxcd/source-controller/internal/oci"
36
35
"github.com/google/go-containerregistry/pkg/authn"
37
36
"github.com/google/go-containerregistry/pkg/authn/k8schain"
@@ -54,16 +53,19 @@ import (
54
53
"sigs.k8s.io/controller-runtime/pkg/predicate"
55
54
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
56
55
56
+ eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
57
57
"github.com/fluxcd/pkg/apis/meta"
58
58
"github.com/fluxcd/pkg/oci"
59
59
"github.com/fluxcd/pkg/oci/auth/login"
60
60
"github.com/fluxcd/pkg/runtime/conditions"
61
61
helper "github.com/fluxcd/pkg/runtime/controller"
62
62
"github.com/fluxcd/pkg/runtime/patch"
63
63
"github.com/fluxcd/pkg/runtime/predicates"
64
+ rreconcile "github.com/fluxcd/pkg/runtime/reconcile"
64
65
"github.com/fluxcd/pkg/sourceignore"
65
66
"github.com/fluxcd/pkg/untar"
66
67
"github.com/fluxcd/pkg/version"
68
+
67
69
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
68
70
serror "github.com/fluxcd/source-controller/internal/error"
69
71
sreconcile "github.com/fluxcd/source-controller/internal/reconcile"
@@ -120,7 +122,7 @@ func (e invalidOCIURLError) Error() string {
120
122
// ociRepositoryReconcileFunc is the function type for all the v1beta2.OCIRepository
121
123
// (sub)reconcile functions. The type implementations are grouped and
122
124
// 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 )
124
126
125
127
// OCIRepositoryReconciler reconciles a v1beta2.OCIRepository object
126
128
type OCIRepositoryReconciler struct {
@@ -131,6 +133,8 @@ type OCIRepositoryReconciler struct {
131
133
Storage * Storage
132
134
ControllerName string
133
135
requeueDependency time.Duration
136
+
137
+ patchOptions []patch.Option
134
138
}
135
139
136
140
type OCIRepositoryReconcilerOptions struct {
@@ -145,6 +149,8 @@ func (r *OCIRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error {
145
149
}
146
150
147
151
func (r * OCIRepositoryReconciler ) SetupWithManagerAndOptions (mgr ctrl.Manager , opts OCIRepositoryReconcilerOptions ) error {
152
+ r .patchOptions = getPatchOptions (ociRepositoryReadyCondition .Owned , r .ControllerName )
153
+
148
154
r .requeueDependency = opts .DependencyRequeueInterval
149
155
150
156
return ctrl .NewControllerManagedBy (mgr ).
@@ -178,18 +184,15 @@ func (r *OCIRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reques
178
184
r .RecordSuspend (ctx , obj , obj .Spec .Suspend )
179
185
180
186
// 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 )
185
188
186
189
// recResult stores the abstracted reconcile result.
187
190
var recResult sreconcile.Result
188
191
189
192
// Always attempt to patch the object and status after each reconciliation
190
193
// NOTE: The final runtime result and error are set in this block.
191
194
defer func () {
192
- summarizeHelper := summarize .NewHelper (r .EventRecorder , patchHelper )
195
+ summarizeHelper := summarize .NewHelper (r .EventRecorder , serialPatcher )
193
196
summarizeOpts := []summarize.Option {
194
197
summarize .WithConditions (ociRepositoryReadyCondition ),
195
198
summarize .WithBiPolarityConditionTypes (sourcev1 .SourceVerifiedCondition ),
@@ -236,19 +239,36 @@ func (r *OCIRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reques
236
239
r .reconcileSource ,
237
240
r .reconcileArtifact ,
238
241
}
239
- recResult , retErr = r .reconcile (ctx , obj , reconcilers )
242
+ recResult , retErr = r .reconcile (ctx , serialPatcher , obj , reconcilers )
240
243
return
241
244
}
242
245
243
246
// reconcile iterates through the ociRepositoryReconcileFunc tasks for the
244
247
// object. It returns early on the first call that returns
245
248
// 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 ) {
247
250
oldObj := obj .DeepCopy ()
248
251
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
+ }
252
272
}
253
273
254
274
// Create temp working dir
@@ -276,7 +296,7 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.O
276
296
277
297
// Run the sub-reconcilers and build the result of reconciliation.
278
298
for _ , rec := range reconcilers {
279
- recResult , err := rec (ctx , obj , & metadata , tmpDir )
299
+ recResult , err := rec (ctx , sp , obj , & metadata , tmpDir )
280
300
// Exit immediately on ResultRequeue.
281
301
if recResult == sreconcile .ResultRequeue {
282
302
return sreconcile .ResultRequeue , nil
@@ -299,7 +319,8 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.O
299
319
300
320
// reconcileSource fetches the upstream OCI artifact metadata and content.
301
321
// 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 ) {
303
324
var auth authn.Authenticator
304
325
305
326
ctxTimeout , cancel := context .WithTimeout (ctx , obj .Spec .Timeout .Duration )
@@ -385,8 +406,14 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
385
406
defer func () {
386
407
if ! obj .GetArtifact ().HasRevision (revision ) {
387
408
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
+ }
390
417
}
391
418
}()
392
419
@@ -876,22 +903,32 @@ func oidcAuth(ctx context.Context, url, provider string) (authn.Authenticator, e
876
903
// condition is added.
877
904
// The hostname of any URL in the Status of the object are updated, to ensure
878
905
// 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 ) {
880
908
// Garbage collect previous advertised artifact(s) from storage
881
909
_ = r .garbageCollect (ctx , obj )
882
910
883
911
// Determine if the advertised artifact is still in storage
912
+ var artifactMissing bool
884
913
if artifact := obj .GetArtifact (); artifact != nil && ! r .Storage .ArtifactExist (* artifact ) {
885
914
obj .Status .Artifact = nil
886
915
obj .Status .URL = ""
916
+ artifactMissing = true
887
917
// Remove the condition as the artifact doesn't exist.
888
918
conditions .Delete (obj , sourcev1 .ArtifactInStorageCondition )
889
919
}
890
920
891
921
// Record that we do not have an artifact
892
922
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 )
894
928
conditions .Delete (obj , sourcev1 .ArtifactInStorageCondition )
929
+ if err := sp .Patch (ctx , obj , r .patchOptions ... ); err != nil {
930
+ return sreconcile .ResultEmpty , err
931
+ }
895
932
return sreconcile .ResultSuccess , nil
896
933
}
897
934
@@ -911,7 +948,8 @@ func (r *OCIRepositoryReconciler) reconcileStorage(ctx context.Context, obj *sou
911
948
// early.
912
949
// On a successful archive, the Artifact in the Status of the object is set,
913
950
// 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 ) {
915
953
revision := metadata .Revision
916
954
917
955
// Create artifact
0 commit comments