@@ -22,13 +22,12 @@ import (
22
22
"net/url"
23
23
"os"
24
24
"path/filepath"
25
- "regexp"
26
25
"strings"
27
26
"time"
28
27
29
28
securejoin "github.com/cyphar/filepath-securejoin"
30
29
"github.com/go-logr/logr"
31
- extgetter "helm.sh/helm/v3/pkg/getter"
30
+ helmgetter "helm.sh/helm/v3/pkg/getter"
32
31
corev1 "k8s.io/api/core/v1"
33
32
"k8s.io/apimachinery/pkg/api/errors"
34
33
apimeta "k8s.io/apimachinery/pkg/api/meta"
@@ -69,7 +68,7 @@ type HelmChartReconciler struct {
69
68
client.Client
70
69
Scheme * runtime.Scheme
71
70
Storage * Storage
72
- Getters extgetter .Providers
71
+ Getters helmgetter .Providers
73
72
EventRecorder kuberecorder.EventRecorder
74
73
ExternalEventRecorder * events.Recorder
75
74
MetricsRecorder * metrics.Recorder
@@ -199,7 +198,7 @@ func (r *HelmChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
199
198
}
200
199
201
200
// Create working directory
202
- workDir , err := os .MkdirTemp ("" , chart .Kind + "-" + chart .Namespace + "-" + chart .Name + "-" )
201
+ workDir , err := os .MkdirTemp ("" , chart .Kind + "-" + chart .Namespace + "-" + chart .Name + "-" )
203
202
if err != nil {
204
203
err = fmt .Errorf ("failed to create temporary working directory: %w" , err )
205
204
chart = sourcev1 .HelmChartNotReady (* chart .DeepCopy (), sourcev1 .ChartPullFailedReason , err .Error ())
@@ -216,21 +215,6 @@ func (r *HelmChartReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
216
215
var reconcileErr error
217
216
switch typedSource := source .(type ) {
218
217
case * sourcev1.HelmRepository :
219
- // TODO: move this to a validation webhook once the discussion around
220
- // certificates has settled: https://github.com/fluxcd/image-reflector-controller/issues/69
221
- if err := validHelmChartName (chart .Spec .Chart ); err != nil {
222
- reconciledChart = sourcev1 .HelmChartNotReady (chart , sourcev1 .ChartPullFailedReason , err .Error ())
223
- log .Error (err , "validation failed" )
224
- if err := r .updateStatus (ctx , req , reconciledChart .Status ); err != nil {
225
- log .Info (fmt .Sprintf ("%v" , reconciledChart .Status ))
226
- log .Error (err , "unable to update status" )
227
- return ctrl.Result {Requeue : true }, err
228
- }
229
- r .event (ctx , reconciledChart , events .EventSeverityError , err .Error ())
230
- r .recordReadiness (ctx , reconciledChart )
231
- // Do not requeue as there is no chance on recovery.
232
- return ctrl.Result {Requeue : false }, nil
233
- }
234
218
reconciledChart , reconcileErr = r .fromHelmRepository (ctx , * typedSource , * chart .DeepCopy (), workDir , changed )
235
219
case * sourcev1.GitRepository , * sourcev1.Bucket :
236
220
reconciledChart , reconcileErr = r .fromTarballArtifact (ctx , * typedSource .GetArtifact (), * chart .DeepCopy (),
@@ -309,10 +293,10 @@ func (r *HelmChartReconciler) getSource(ctx context.Context, chart sourcev1.Helm
309
293
func (r * HelmChartReconciler ) fromHelmRepository (ctx context.Context , repo sourcev1.HelmRepository , c sourcev1.HelmChart ,
310
294
workDir string , force bool ) (sourcev1.HelmChart , error ) {
311
295
// Configure Index getter options
312
- clientOpts := []extgetter .Option {
313
- extgetter .WithURL (repo .Spec .URL ),
314
- extgetter .WithTimeout (repo .Spec .Timeout .Duration ),
315
- extgetter .WithPassCredentialsAll (repo .Spec .PassCredentials ),
296
+ clientOpts := []helmgetter .Option {
297
+ helmgetter .WithURL (repo .Spec .URL ),
298
+ helmgetter .WithTimeout (repo .Spec .Timeout .Duration ),
299
+ helmgetter .WithPassCredentialsAll (repo .Spec .PassCredentials ),
316
300
}
317
301
if secret , err := r .getHelmRepositorySecret (ctx , & repo ); err != nil {
318
302
return sourcev1 .HelmChartNotReady (c , sourcev1 .AuthenticationFailedReason , err .Error ()), err
@@ -423,7 +407,7 @@ func (r *HelmChartReconciler) fromTarballArtifact(ctx context.Context, source so
423
407
err = fmt .Errorf ("artifact untar error: %w" , err )
424
408
return sourcev1 .HelmChartNotReady (c , sourcev1 .StorageOperationFailedReason , err .Error ()), err
425
409
}
426
- if err = f .Close (); err != nil {
410
+ if err = f .Close (); err != nil {
427
411
err = fmt .Errorf ("artifact close error: %w" , err )
428
412
return sourcev1 .HelmChartNotReady (c , sourcev1 .StorageOperationFailedReason , err .Error ()), err
429
413
}
@@ -440,20 +424,17 @@ func (r *HelmChartReconciler) fromTarballArtifact(ctx context.Context, source so
440
424
return sourcev1 .HelmChartNotReady (c , sourcev1 .StorageOperationFailedReason , err .Error ()), err
441
425
}
442
426
dm := chart .NewDependencyManager (
443
- chart .WithRepositoryCallback (r .getNamespacedChartRepositoryCallback (ctx , authDir , c .GetNamespace ())),
427
+ chart .WithRepositoryCallback (r .namespacedChartRepositoryCallback (ctx , authDir , c .GetNamespace ())),
444
428
)
445
429
defer dm .Clear ()
446
430
447
- // Get any cached chart
448
- var cachedChart string
449
- if artifact := c .Status .Artifact ; artifact != nil {
450
- cachedChart = artifact .Path
451
- }
452
-
431
+ // Configure builder options, including any previously cached chart
453
432
buildsOpts := chart.BuildOptions {
454
- ValueFiles : c .GetValuesFiles (),
455
- CachedChart : cachedChart ,
456
- Force : force ,
433
+ ValueFiles : c .GetValuesFiles (),
434
+ Force : force ,
435
+ }
436
+ if artifact := c .Status .Artifact ; artifact != nil {
437
+ buildsOpts .CachedChart = artifact .Path
457
438
}
458
439
459
440
// Add revision metadata to chart build
@@ -465,7 +446,7 @@ func (r *HelmChartReconciler) fromTarballArtifact(ctx context.Context, source so
465
446
466
447
// Build chart
467
448
chartB := chart .NewLocalBuilder (dm )
468
- build , err := chartB .Build (ctx , chart.LocalReference {BaseDir : sourceDir , Path : chartPath }, filepath .Join (workDir , "chart.tgz" ), buildsOpts )
449
+ build , err := chartB .Build (ctx , chart.LocalReference {WorkDir : sourceDir , Path : chartPath }, filepath .Join (workDir , "chart.tgz" ), buildsOpts )
469
450
if err != nil {
470
451
return sourcev1 .HelmChartNotReady (c , sourcev1 .ChartPackageFailedReason , err .Error ()), err
471
452
}
@@ -475,7 +456,8 @@ func (r *HelmChartReconciler) fromTarballArtifact(ctx context.Context, source so
475
456
476
457
// If the path of the returned build equals the cache path,
477
458
// there are no changes to the chart
478
- if build .Path == cachedChart {
459
+ if apimeta .IsStatusConditionTrue (c .Status .Conditions , meta .ReadyCondition ) &&
460
+ build .Path == buildsOpts .CachedChart {
479
461
// Ensure hostname is updated
480
462
if c .GetArtifact ().URL != newArtifact .URL {
481
463
r .Storage .SetArtifactURL (c .GetArtifact ())
@@ -515,11 +497,17 @@ func (r *HelmChartReconciler) fromTarballArtifact(ctx context.Context, source so
515
497
return sourcev1 .HelmChartReady (c , newArtifact , cUrl , sourcev1 .ChartPackageSucceededReason , build .Summary ()), nil
516
498
}
517
499
518
- // TODO(hidde): factor out to helper?
519
- func (r * HelmChartReconciler ) getNamespacedChartRepositoryCallback (ctx context.Context , dir , namespace string ) chart.GetChartRepositoryCallback {
500
+ // namespacedChartRepositoryCallback returns a chart.GetChartRepositoryCallback
501
+ // scoped to the given namespace. Credentials for retrieved v1beta1.HelmRepository
502
+ // objects are stored in the given directory.
503
+ // The returned callback returns a repository.ChartRepository configured with the
504
+ // retrieved v1beta1.HelmRepository, or a shim with defaults if no object could
505
+ // be found.
506
+ func (r * HelmChartReconciler ) namespacedChartRepositoryCallback (ctx context.Context , dir , namespace string ) chart.GetChartRepositoryCallback {
520
507
return func (url string ) (* repository.ChartRepository , error ) {
521
508
repo , err := r .resolveDependencyRepository (ctx , url , namespace )
522
509
if err != nil {
510
+ // Return Kubernetes client errors, but ignore others
523
511
if errors .ReasonForError (err ) != metav1 .StatusReasonUnknown {
524
512
return nil , err
525
513
}
@@ -530,10 +518,10 @@ func (r *HelmChartReconciler) getNamespacedChartRepositoryCallback(ctx context.C
530
518
},
531
519
}
532
520
}
533
- clientOpts := []extgetter .Option {
534
- extgetter .WithURL (repo .Spec .URL ),
535
- extgetter .WithTimeout (repo .Spec .Timeout .Duration ),
536
- extgetter .WithPassCredentialsAll (repo .Spec .PassCredentials ),
521
+ clientOpts := []helmgetter .Option {
522
+ helmgetter .WithURL (repo .Spec .URL ),
523
+ helmgetter .WithTimeout (repo .Spec .Timeout .Duration ),
524
+ helmgetter .WithPassCredentialsAll (repo .Spec .PassCredentials ),
537
525
}
538
526
if secret , err := r .getHelmRepositorySecret (ctx , repo ); err != nil {
539
527
return nil , err
@@ -801,18 +789,6 @@ func (r *HelmChartReconciler) requestsForBucketChange(o client.Object) []reconci
801
789
return reqs
802
790
}
803
791
804
- // validHelmChartName returns an error if the given string is not a
805
- // valid Helm chart name; a valid name must be lower case letters
806
- // and numbers, words may be separated with dashes (-).
807
- // Ref: https://helm.sh/docs/chart_best_practices/conventions/#chart-names
808
- func validHelmChartName (s string ) error {
809
- chartFmt := regexp .MustCompile ("^([-a-z0-9]*)$" )
810
- if ! chartFmt .MatchString (s ) {
811
- return fmt .Errorf ("invalid chart name %q, a valid name must be lower case letters and numbers and MAY be separated with dashes (-)" , s )
812
- }
813
- return nil
814
- }
815
-
816
792
func (r * HelmChartReconciler ) recordSuspension (ctx context.Context , chart sourcev1.HelmChart ) {
817
793
if r .MetricsRecorder == nil {
818
794
return
0 commit comments