@@ -314,13 +314,7 @@ func (r *HelmChartReconciler) reconcileStorage(ctx context.Context, obj *sourcev
314
314
return sreconcile .ResultSuccess , nil
315
315
}
316
316
317
- // reconcileSource reconciles the upstream bucket with the client for the given object's Provider, and returns the
318
- // result.
319
- // If a SecretRef is defined, it attempts to fetch the Secret before calling the provider. If the fetch of the Secret
320
- // fails, it records v1beta1.FetchFailedCondition=True and returns early.
321
- //
322
- // The caller should assume a failure if an error is returned, or the BuildResult is zero.
323
- func (r * HelmChartReconciler ) reconcileSource (ctx context.Context , obj * sourcev1.HelmChart , build * chart.Build ) (sreconcile.Result , error ) {
317
+ func (r * HelmChartReconciler ) reconcileSource (ctx context.Context , obj * sourcev1.HelmChart , build * chart.Build ) (_ sreconcile.Result , retErr error ) {
324
318
// Retrieve the source
325
319
s , err := r .getSource (ctx , obj )
326
320
if err != nil {
@@ -332,7 +326,7 @@ func (r *HelmChartReconciler) reconcileSource(ctx context.Context, obj *sourcev1
332
326
333
327
// Return Kubernetes client errors, but ignore others which can only be
334
328
// solved by a change in generation
335
- if apierrs .ReasonForError (err ) ! = metav1 .StatusReasonUnknown {
329
+ if apierrs .ReasonForError (err ) = = metav1 .StatusReasonUnknown {
336
330
return sreconcile .ResultEmpty , & serror.Stalling {
337
331
Err : fmt .Errorf ("failed to get source: %w" , err ),
338
332
Reason : "UnsupportedSourceKind" ,
@@ -353,20 +347,52 @@ func (r *HelmChartReconciler) reconcileSource(ctx context.Context, obj *sourcev1
353
347
// Record current artifact revision as last observed
354
348
obj .Status .ObservedSourceArtifactRevision = s .GetArtifact ().Revision
355
349
356
- // Perform the reconciliation for the chart source type
350
+ // Defer observation of build result
351
+ defer func () {
352
+ // Record both success and error observations on the object
353
+ observeChartBuild (obj , build , retErr )
354
+
355
+ // If we actually build a chart, take a historical note of any dependencies we resolved.
356
+ // The reason this is a done conditionally, is because if we have a cached one in storage,
357
+ // we can not recover this information (and put it in a condition). Which would result in
358
+ // a sudden (partial) disappearance of observed state.
359
+ // TODO(hidde): include specific name/version information?
360
+ if depNum := build .ResolvedDependencies ; build .Complete () && depNum > 0 {
361
+ r .Eventf (obj , corev1 .EventTypeNormal , "ResolvedDependencies" , "Resolved %d chart dependencies" , depNum )
362
+ }
363
+
364
+ // Handle any build error
365
+ if retErr != nil {
366
+ e := fmt .Errorf ("failed to build chart from source artifact: %w" , retErr )
367
+ retErr = & serror.Event {
368
+ Err : e ,
369
+ Reason : meta .FailedReason ,
370
+ }
371
+ if buildErr := new (chart.BuildError ); errors .As (e , & buildErr ) {
372
+ if chart .IsPersistentBuildErrorReason (buildErr .Reason ) {
373
+ retErr = & serror.Stalling {
374
+ Err : e ,
375
+ Reason : buildErr .Reason .Reason ,
376
+ }
377
+ }
378
+ }
379
+ }
380
+ }()
381
+
382
+ // Perform the build for the chart source type
357
383
switch typedSource := s .(type ) {
358
384
case * sourcev1.HelmRepository :
359
- return r .reconcileFromHelmRepository (ctx , obj , typedSource , build )
385
+ return r .buildFromHelmRepository (ctx , obj , typedSource , build )
360
386
case * sourcev1.GitRepository , * sourcev1.Bucket :
361
- return r .reconcileFromTarballArtifact (ctx , obj , * typedSource .GetArtifact (), build )
387
+ return r .buildFromTarballArtifact (ctx , obj , * typedSource .GetArtifact (), build )
362
388
default :
363
389
// Ending up here should generally not be possible
364
390
// as getSource already validates
365
391
return sreconcile .ResultEmpty , nil
366
392
}
367
393
}
368
394
369
- func (r * HelmChartReconciler ) reconcileFromHelmRepository (ctx context.Context , obj * sourcev1.HelmChart ,
395
+ func (r * HelmChartReconciler ) buildFromHelmRepository (ctx context.Context , obj * sourcev1.HelmChart ,
370
396
repo * sourcev1.HelmRepository , b * chart.Build ) (sreconcile.Result , error ) {
371
397
372
398
// Construct the Getter options from the HelmRepository data
@@ -454,34 +480,15 @@ func (r *HelmChartReconciler) reconcileFromHelmRepository(ctx context.Context, o
454
480
// Build the chart
455
481
ref := chart.RemoteReference {Name : obj .Spec .Chart , Version : obj .Spec .Version }
456
482
build , err := cb .Build (ctx , ref , util .TempPathForObj ("" , ".tgz" , obj ), opts )
457
-
458
- // Record both success _and_ error observations on the object
459
- processChartBuild (obj , build , err )
460
-
461
- // Handle any build error
462
483
if err != nil {
463
- e := fmt .Errorf ("failed to build chart from remote source: %w" , err )
464
- reason := meta .FailedReason
465
- if buildErr := new (chart.BuildError ); errors .As (err , & buildErr ) {
466
- reason = buildErr .Reason .Reason
467
- if chart .IsPersistentBuildErrorReason (buildErr .Reason ) {
468
- return sreconcile .ResultEmpty , & serror.Stalling {
469
- Err : e ,
470
- Reason : reason ,
471
- }
472
- }
473
- }
474
- return sreconcile .ResultEmpty , & serror.Event {
475
- Err : e ,
476
- Reason : reason ,
477
- }
484
+ return sreconcile .ResultEmpty , err
478
485
}
479
486
480
487
* b = * build
481
488
return sreconcile .ResultSuccess , nil
482
489
}
483
490
484
- func (r * HelmChartReconciler ) reconcileFromTarballArtifact (ctx context.Context , obj * sourcev1.HelmChart , source sourcev1.Artifact , b * chart.Build ) (sreconcile.Result , error ) {
491
+ func (r * HelmChartReconciler ) buildFromTarballArtifact (ctx context.Context , obj * sourcev1.HelmChart , source sourcev1.Artifact , b * chart.Build ) (sreconcile.Result , error ) {
485
492
// Create temporary working directory
486
493
tmpDir , err := util .TempDirForObj ("" , obj )
487
494
if err != nil {
@@ -533,7 +540,7 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
533
540
chartPath , err := securejoin .SecureJoin (sourceDir , obj .Spec .Chart )
534
541
if err != nil {
535
542
e := & serror.Stalling {
536
- Err : fmt .Errorf ("Path calculation for chart '%s' failed: %w" , obj .Spec .Chart , err ),
543
+ Err : fmt .Errorf ("path calculation for chart '%s' failed: %w" , obj .Spec .Chart , err ),
537
544
Reason : "IllegalPath" ,
538
545
}
539
546
conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , "IllegalPath" , e .Err .Error ())
@@ -563,12 +570,6 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
563
570
opts .CachedChart = r .Storage .LocalPath (* artifact )
564
571
}
565
572
566
- // Add revision metadata to chart build
567
- if obj .Spec .ReconcileStrategy == sourcev1 .ReconcileStrategyRevision {
568
- // Isolate the commit SHA from GitRepository type artifacts by removing the branch/ prefix.
569
- splitRev := strings .Split (source .Revision , "/" )
570
- opts .VersionMetadata = splitRev [len (splitRev )- 1 ]
571
- }
572
573
// Configure revision metadata for chart build if we should react to revision changes
573
574
if obj .Spec .ReconcileStrategy == sourcev1 .ReconcileStrategyRevision {
574
575
rev := source .Revision
@@ -593,43 +594,23 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
593
594
}
594
595
opts .VersionMetadata = rev
595
596
}
597
+ // Set the VersionMetadata to the object's Generation if ValuesFiles is defined,
598
+ // this ensures changes can be noticed by the Artifact consumer
599
+ if len (opts .GetValuesFiles ()) > 0 {
600
+ if opts .VersionMetadata != "" {
601
+ opts .VersionMetadata += "."
602
+ }
603
+ opts .VersionMetadata += strconv .FormatInt (obj .Generation , 10 )
604
+ }
596
605
597
606
// Build chart
598
607
cb := chart .NewLocalBuilder (dm )
599
608
build , err := cb .Build (ctx , chart.LocalReference {
600
609
WorkDir : sourceDir ,
601
610
Path : chartPath ,
602
611
}, util .TempPathForObj ("" , ".tgz" , obj ), opts )
603
-
604
- // Record both success _and_ error observations on the object
605
- processChartBuild (obj , build , err )
606
-
607
- // Handle any build error
608
612
if err != nil {
609
- e := fmt .Errorf ("failed to build chart from source artifact: %w" , err )
610
- reason := meta .FailedReason
611
- if buildErr := new (chart.BuildError ); errors .As (err , & buildErr ) {
612
- reason = buildErr .Reason .Reason
613
- if chart .IsPersistentBuildErrorReason (buildErr .Reason ) {
614
- return sreconcile .ResultEmpty , & serror.Stalling {
615
- Err : e ,
616
- Reason : reason ,
617
- }
618
- }
619
- }
620
- return sreconcile .ResultEmpty , & serror.Event {
621
- Err : e ,
622
- Reason : reason ,
623
- }
624
- }
625
-
626
- // If we actually build a chart, take a historical note of any dependencies we resolved.
627
- // The reason this is a done conditionally, is because if we have a cached one in storage,
628
- // we can not recover this information (and put it in a condition). Which would result in
629
- // a sudden (partial) disappearance of observed state.
630
- // TODO(hidde): include specific name/version information?
631
- if depNum := build .ResolvedDependencies ; depNum > 0 {
632
- r .eventLogf (ctx , obj , corev1 .EventTypeNormal , "ResolvedDependencies" , "resolved %d chart dependencies" , depNum )
613
+ return sreconcile .ResultEmpty , err
633
614
}
634
615
635
616
* b = * build
@@ -761,7 +742,7 @@ func (r *HelmChartReconciler) reconcileDelete(ctx context.Context, obj *sourcev1
761
742
}
762
743
763
744
// garbageCollect performs a garbage collection for the given v1beta1.HelmChart. It removes all but the current
764
- // artifact except for when the deletion timestamp is set, which will result in the removal of all artifacts for the
745
+ // artifact, unless the deletion timestamp is set. Which will result in the removal of all artifacts for the
765
746
// resource.
766
747
func (r * HelmChartReconciler ) garbageCollect (ctx context.Context , obj * sourcev1.HelmChart ) error {
767
748
if ! obj .DeletionTimestamp .IsZero () {
@@ -839,6 +820,7 @@ func (r *HelmChartReconciler) resolveDependencyRepository(ctx context.Context, u
839
820
listOpts := []client.ListOption {
840
821
client .InNamespace (namespace ),
841
822
client.MatchingFields {sourcev1 .HelmRepositoryURLIndexKey : url },
823
+ client .Limit (1 ),
842
824
}
843
825
var list sourcev1.HelmRepositoryList
844
826
err := r .Client .List (ctx , & list , listOpts ... )
@@ -968,54 +950,60 @@ func (r *HelmChartReconciler) requestsForBucketChange(o client.Object) []reconci
968
950
return reqs
969
951
}
970
952
971
- func processChartBuild (obj * sourcev1.HelmChart , build * chart.Build , err error ) {
953
+ // eventLogf records event and logs at the same time. This log is different from
954
+ // the debug log in the event recorder in the sense that this is a simple log,
955
+ // the event recorder debug log contains complete details about the event.
956
+ func (r * HelmChartReconciler ) eventLogf (ctx context.Context , obj runtime.Object , eventType string , reason string , messageFmt string , args ... interface {}) {
957
+ msg := fmt .Sprintf (messageFmt , args ... )
958
+ // Log and emit event.
959
+ if eventType == corev1 .EventTypeWarning {
960
+ ctrl .LoggerFrom (ctx ).Error (errors .New (reason ), msg )
961
+ } else {
962
+ ctrl .LoggerFrom (ctx ).Info (msg )
963
+ }
964
+ r .Eventf (obj , eventType , reason , msg )
965
+ }
966
+
967
+ // observeChartBuild records the observation on the given given build and error on the object.
968
+ func observeChartBuild (obj * sourcev1.HelmChart , build * chart.Build , err error ) {
972
969
if build .HasMetadata () {
973
970
if build .Name != obj .Status .ObservedChartName || ! obj .GetArtifact ().HasRevision (build .Version ) {
974
971
conditions .MarkTrue (obj , sourcev1 .ArtifactOutdatedCondition , "NewChart" , build .Summary ())
975
972
}
976
973
}
977
974
978
- if err == nil {
975
+ if build . Complete () {
979
976
conditions .Delete (obj , sourcev1 .FetchFailedCondition )
980
977
conditions .Delete (obj , sourcev1 .BuildFailedCondition )
981
- return
982
978
}
983
979
984
- var buildErr * chart.BuildError
985
- if ok := errors .As (err , & buildErr ); ! ok {
986
- buildErr = & chart.BuildError {
987
- Reason : chart .ErrUnknown ,
988
- Err : err ,
980
+ if err != nil {
981
+ var buildErr * chart.BuildError
982
+ if ok := errors .As (err , & buildErr ); ! ok {
983
+ buildErr = & chart.BuildError {
984
+ Reason : chart .ErrUnknown ,
985
+ Err : err ,
986
+ }
989
987
}
990
- }
991
988
992
- switch buildErr .Reason {
993
- case chart .ErrChartMetadataPatch , chart .ErrValuesFilesMerge , chart .ErrDependencyBuild , chart .ErrChartPackage :
994
- conditions .Delete (obj , sourcev1 .FetchFailedCondition )
995
- conditions .MarkTrue (obj , sourcev1 .BuildFailedCondition , buildErr .Reason .Reason , buildErr .Error ())
996
- default :
997
- conditions .Delete (obj , sourcev1 .BuildFailedCondition )
998
- conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , buildErr .Reason .Reason , buildErr .Error ())
989
+ switch buildErr .Reason {
990
+ case chart .ErrChartMetadataPatch , chart .ErrValuesFilesMerge , chart .ErrDependencyBuild , chart .ErrChartPackage :
991
+ conditions .Delete (obj , sourcev1 .FetchFailedCondition )
992
+ conditions .MarkTrue (obj , sourcev1 .BuildFailedCondition , buildErr .Reason .Reason , buildErr .Error ())
993
+ default :
994
+ conditions .Delete (obj , sourcev1 .BuildFailedCondition )
995
+ conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , buildErr .Reason .Reason , buildErr .Error ())
996
+ }
997
+ return
999
998
}
1000
999
}
1001
1000
1002
1001
func reasonForBuild (build * chart.Build ) string {
1002
+ if ! build .Complete () {
1003
+ return ""
1004
+ }
1003
1005
if build .Packaged {
1004
1006
return sourcev1 .ChartPackageSucceededReason
1005
1007
}
1006
1008
return sourcev1 .ChartPullSucceededReason
1007
1009
}
1008
-
1009
- // eventLog records event and logs at the same time. This log is different from
1010
- // the debug log in the event recorder in the sense that this is a simple log,
1011
- // the event recorder debug log contains complete details about the event.
1012
- func (r * HelmChartReconciler ) eventLogf (ctx context.Context , obj runtime.Object , eventType string , reason string , messageFmt string , args ... interface {}) {
1013
- msg := fmt .Sprintf (messageFmt , args ... )
1014
- // Log and emit event.
1015
- if eventType == corev1 .EventTypeWarning {
1016
- ctrl .LoggerFrom (ctx ).Error (errors .New (reason ), msg )
1017
- } else {
1018
- ctrl .LoggerFrom (ctx ).Info (msg )
1019
- }
1020
- r .Eventf (obj , eventType , reason , msg )
1021
- }
0 commit comments