@@ -19,6 +19,7 @@ package controllers
1919import (
2020 "context"
2121 "fmt"
22+ "io"
2223 "io/ioutil"
2324 "net/url"
2425 "os"
@@ -104,7 +105,7 @@ func (r *HelmChartReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
104105 }
105106 }
106107
107- // set initial status
108+ // Conditionally set progressing condition in status
108109 if resetChart , ok := r .resetStatus (chart ); ok {
109110 chart = resetChart
110111 if err := r .Status ().Update (ctx , & chart ); err != nil {
@@ -113,11 +114,12 @@ func (r *HelmChartReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
113114 }
114115 }
115116
116- // purge old artifacts from storage
117+ // Purge all but current artifact from storage
117118 if err := r .gc (chart , false ); err != nil {
118119 log .Error (err , "unable to purge old artifacts" )
119120 }
120121
122+ // Perform the reconciliation for the chart source type
121123 var reconciledChart sourcev1.HelmChart
122124 var reconcileErr error
123125 switch chart .Spec .SourceRef .Kind {
@@ -146,19 +148,19 @@ func (r *HelmChartReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
146148 return ctrl.Result {}, err
147149 }
148150
149- // update status with the reconciliation result
151+ // Update status with the reconciliation result
150152 if err := r .Status ().Update (ctx , & reconciledChart ); err != nil {
151153 log .Error (err , "unable to update status" )
152154 return ctrl.Result {Requeue : true }, err
153155 }
154156
155- // if reconciliation failed, record the failure and requeue immediately
157+ // If reconciliation failed, record the failure and requeue immediately
156158 if reconcileErr != nil {
157159 r .event (reconciledChart , recorder .EventSeverityError , reconcileErr .Error ())
158160 return ctrl.Result {Requeue : true }, reconcileErr
159161 }
160162
161- // emit revision change event
163+ // Emit an event if we did not have an artifact before, or the revision has changed
162164 if chart .Status .Artifact == nil || reconciledChart .Status .Artifact .Revision != chart .Status .Artifact .Revision {
163165 r .event (reconciledChart , recorder .EventSeverityInfo , sourcev1 .HelmChartReadyMessage (reconciledChart ))
164166 }
@@ -167,7 +169,6 @@ func (r *HelmChartReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
167169 time .Now ().Sub (start ).String (),
168170 chart .GetInterval ().Duration .String (),
169171 ))
170-
171172 return ctrl.Result {RequeueAfter : chart .GetInterval ().Duration }, nil
172173}
173174
@@ -195,8 +196,9 @@ func (r *HelmChartReconciler) reconcileFromHelmRepository(ctx context.Context,
195196 return sourcev1 .HelmChartNotReady (chart , sourcev1 .ChartPullFailedReason , err .Error ()), err
196197 }
197198
198- // return early on unchanged chart version
199- artifact := r .Storage .NewArtifactFor (chart .Kind , chart .GetObjectMeta (), cv .Version , fmt .Sprintf ("%s-%s.tgz" , cv .Name , cv .Version ))
199+ // Return early if the revision is still the same as the current artifact
200+ artifact := r .Storage .NewArtifactFor (chart .Kind , chart .GetObjectMeta (), cv .Version ,
201+ fmt .Sprintf ("%s-%s.tgz" , cv .Name , cv .Version ))
200202 if repository .GetArtifact () != nil && repository .GetArtifact ().Revision == cv .Version {
201203 if artifact .URL != repository .GetArtifact ().URL {
202204 r .Storage .SetArtifactURL (repository .GetArtifact ())
@@ -228,6 +230,7 @@ func (r *HelmChartReconciler) reconcileFromHelmRepository(ctx context.Context,
228230 u .RawQuery = q .Encode ()
229231 }
230232
233+ // Get the getter for the protocol
231234 c , err := r .Getters .ByScheme (u .Scheme )
232235 if err != nil {
233236 return sourcev1 .HelmChartNotReady (chart , sourcev1 .ChartPullFailedReason , err .Error ()), err
@@ -258,35 +261,35 @@ func (r *HelmChartReconciler) reconcileFromHelmRepository(ctx context.Context,
258261 clientOpts = opts
259262 }
260263
261- // TODO(hidde): implement timeout from the HelmRepository
262- // https://github.com/helm/helm/pull/7950
263- res , err := c .Get (u .String (), clientOpts ... )
264- if err != nil {
265- return sourcev1 .HelmChartNotReady (chart , sourcev1 .ChartPullFailedReason , err .Error ()), err
266- }
267-
268- // create artifact dir
264+ // Ensure artifact directory exists
269265 err = r .Storage .MkdirAll (artifact )
270266 if err != nil {
271267 err = fmt .Errorf ("unable to create chart directory: %w" , err )
272268 return sourcev1 .HelmChartNotReady (chart , sourcev1 .StorageOperationFailedReason , err .Error ()), err
273269 }
274270
275- // acquire lock
271+ // Acquire a lock for the artifact
276272 unlock , err := r .Storage .Lock (artifact )
277273 if err != nil {
278274 err = fmt .Errorf ("unable to acquire lock: %w" , err )
279275 return sourcev1 .HelmChartNotReady (chart , sourcev1 .StorageOperationFailedReason , err .Error ()), err
280276 }
281277 defer unlock ()
282278
283- // save artifact to storage
279+ // TODO(hidde): implement timeout from the HelmRepository
280+ // https://github.com/helm/helm/pull/7950
281+ res , err := c .Get (u .String (), clientOpts ... )
282+ if err != nil {
283+ return sourcev1 .HelmChartNotReady (chart , sourcev1 .ChartPullFailedReason , err .Error ()), err
284+ }
285+
286+ // Write the artifact to storage
284287 if err := r .Storage .AtomicWriteFile (& artifact , res , 0644 ); err != nil {
285288 err = fmt .Errorf ("unable to write chart file: %w" , err )
286289 return sourcev1 .HelmChartNotReady (chart , sourcev1 .StorageOperationFailedReason , err .Error ()), err
287290 }
288291
289- // update symlink
292+ // Update symlink
290293 chartUrl , err := r .Storage .Symlink (artifact , fmt .Sprintf ("%s-latest.tgz" , cv .Name ))
291294 if err != nil {
292295 err = fmt .Errorf ("storage error: %w" , err )
@@ -297,7 +300,7 @@ func (r *HelmChartReconciler) reconcileFromHelmRepository(ctx context.Context,
297300 return sourcev1 .HelmChartReady (chart , artifact , chartUrl , sourcev1 .ChartPullSucceededReason , message ), nil
298301}
299302
300- // getChartRepositoryWithArtifact attempts to get the ChartRepository
303+ // getChartRepositoryWithArtifact attempts to get the v1alpha1.HelmRepository
301304// for the given chart. It returns an error if the HelmRepository could
302305// not be retrieved or if does not have an artifact.
303306func (r * HelmChartReconciler ) getChartRepositoryWithArtifact (ctx context.Context , chart sourcev1.HelmChart ) (sourcev1.HelmRepository , error ) {
@@ -318,50 +321,50 @@ func (r *HelmChartReconciler) getChartRepositoryWithArtifact(ctx context.Context
318321 }
319322
320323 if repository .GetArtifact () == nil {
321- err = fmt .Errorf ("no repository index artifact found in HelmRepository '%s'" , repository . Name )
324+ err = fmt .Errorf ("no repository index artifact found in HelmRepository '%s'" , name )
322325 }
323326
324327 return repository , err
325328}
326329
327330func (r * HelmChartReconciler ) reconcileFromGitRepository (ctx context.Context ,
328331 repository sourcev1.GitRepository , chart sourcev1.HelmChart ) (sourcev1.HelmChart , error ) {
329- // create tmp dir
332+ // Create temporary working directory
330333 tmpDir , err := ioutil .TempDir ("" , fmt .Sprintf ("%s-%s" , chart .Namespace , chart .Name ))
331334 if err != nil {
332335 err = fmt .Errorf ("tmp dir error: %w" , err )
333336 return sourcev1 .HelmChartNotReady (chart , sourcev1 .StorageOperationFailedReason , err .Error ()), err
334337 }
335338 defer os .RemoveAll (tmpDir )
336339
337- // open file
340+ // Open GitRepository artifact file and untar files into working directory
338341 f , err := os .Open (r .Storage .LocalPath (* repository .GetArtifact ()))
339342 if err != nil {
340343 err = fmt .Errorf ("artifact open error: %w" , err )
341344 return sourcev1 .HelmChartNotReady (chart , sourcev1 .StorageOperationFailedReason , err .Error ()), err
342345 }
343-
344- // extract artifact files
345346 if _ , err = untar .Untar (f , tmpDir ); err != nil {
347+ f .Close ()
346348 err = fmt .Errorf ("artifact untar error: %w" , err )
347349 return sourcev1 .HelmChartNotReady (chart , sourcev1 .StorageOperationFailedReason , err .Error ()), err
348350 }
351+ f .Close ()
349352
350- // ensure configured path is a chart directory
353+ // Ensure configured path is a chart directory
351354 chartPath := path .Join (tmpDir , chart .Spec .Chart )
352355 if _ , err := chartutil .IsChartDir (chartPath ); err != nil {
353356 err = fmt .Errorf ("chart path error: %w" , err )
354357 return sourcev1 .HelmChartNotReady (chart , sourcev1 .StorageOperationFailedReason , err .Error ()), err
355358 }
356359
357- // read chart metadata
360+ // Read the chart metadata
358361 chartMetadata , err := chartutil .LoadChartfile (path .Join (chartPath , chartutil .ChartfileName ))
359362 if err != nil {
360363 err = fmt .Errorf ("load chart metadata error: %w" , err )
361364 return sourcev1 .HelmChartNotReady (chart , sourcev1 .StorageOperationFailedReason , err .Error ()), err
362365 }
363366
364- // return early on unchanged chart version
367+ // Return early if the revision is still the same as the current chart artifact
365368 artifact := r .Storage .NewArtifactFor (chart .Kind , chart .ObjectMeta .GetObjectMeta (), chartMetadata .Version , fmt .Sprintf ("%s-%s.tgz" , chartMetadata .Name , chartMetadata .Version ))
366369 if chart .GetArtifact () != nil && chart .GetArtifact ().Revision == chartMetadata .Version {
367370 if artifact .URL != repository .GetArtifact ().URL {
@@ -371,22 +374,51 @@ func (r *HelmChartReconciler) reconcileFromGitRepository(ctx context.Context,
371374 return chart , nil
372375 }
373376
374- // create artifact dir
377+ // Overwrite default values if instructed to
378+ if chart .Spec .ValuesFile != "" {
379+ srcPath := path .Join (tmpDir , chart .Spec .ValuesFile )
380+ if f , err := os .Stat (srcPath ); os .IsNotExist (err ) || ! f .Mode ().IsRegular () {
381+ err = fmt .Errorf ("invalid values file path: %s" , chart .Spec .ValuesFile )
382+ return chart , err
383+ }
384+ src , err := os .Open (srcPath )
385+ if err != nil {
386+ err = fmt .Errorf ("failed to open values file '%s': %w" , chart .Spec .ValuesFile , err )
387+ return chart , err
388+ }
389+ t , err := os .OpenFile (path .Join (tmpDir , chartutil .ValuesfileName ), os .O_RDWR | os .O_CREATE | os .O_TRUNC , 0644 )
390+ if err != nil {
391+ src .Close ()
392+ err = fmt .Errorf ("failed to open values file '%s': %w" , chartutil .ValuesfileName , err )
393+ return chart , err
394+ }
395+ if _ , err := io .Copy (t , src ); err != nil {
396+ t .Close ()
397+ src .Close ()
398+ err = fmt .Errorf ("failed to copy values file '%s' to '%s: %w" , chart .Spec .ValuesFile , chartutil .ValuesfileName , err )
399+ return chart , err
400+ }
401+ t .Close ()
402+ src .Close ()
403+ }
404+
405+ // Ensure artifact directory exists
375406 err = r .Storage .MkdirAll (artifact )
376407 if err != nil {
377408 err = fmt .Errorf ("unable to create artifact directory: %w" , err )
378409 return sourcev1 .HelmChartNotReady (chart , sourcev1 .StorageOperationFailedReason , err .Error ()), err
379410 }
380411
381- // acquire lock
412+ // Acquire a lock for the artifact
382413 unlock , err := r .Storage .Lock (artifact )
383414 if err != nil {
384415 err = fmt .Errorf ("unable to acquire lock: %w" , err )
385416 return sourcev1 .HelmChartNotReady (chart , sourcev1 .StorageOperationFailedReason , err .Error ()), err
386417 }
387418 defer unlock ()
388419
389- // package chart
420+ // Package the chart, we use the action here instead of relying on the
421+ // chartutil.Save method as the action performs a dependency check for us
390422 pkg := action .NewPackage ()
391423 pkg .Destination = tmpDir
392424 src , err := pkg .Run (chartPath , nil )
@@ -395,7 +427,7 @@ func (r *HelmChartReconciler) reconcileFromGitRepository(ctx context.Context,
395427 return sourcev1 .HelmChartNotReady (chart , sourcev1 .ChartPackageFailedReason , err .Error ()), err
396428 }
397429
398- // copy chart package
430+ // Copy the packaged chart to the artifact path
399431 cf , err := os .Open (src )
400432 if err != nil {
401433 err = fmt .Errorf ("failed to open chart package: %w" , err )
@@ -408,7 +440,7 @@ func (r *HelmChartReconciler) reconcileFromGitRepository(ctx context.Context,
408440 }
409441 cf .Close ()
410442
411- // update symlink
443+ // Update symlink
412444 cUrl , err := r .Storage .Symlink (artifact , fmt .Sprintf ("%s-latest.tgz" , chartMetadata .Name ))
413445 if err != nil {
414446 err = fmt .Errorf ("storage error: %w" , err )
@@ -420,8 +452,8 @@ func (r *HelmChartReconciler) reconcileFromGitRepository(ctx context.Context,
420452}
421453
422454// getGitRepositoryWithArtifact attempts to get the GitRepository for the given
423- // chart. It returns an error if the GitRepository could not be retrieved or
424- // does not have an artifact.
455+ // chart. It returns an error if the v1alpha1. GitRepository could not be retrieved
456+ // or does not have an artifact.
425457func (r * HelmChartReconciler ) getGitRepositoryWithArtifact (ctx context.Context , chart sourcev1.HelmChart ) (sourcev1.GitRepository , error ) {
426458 if chart .Spec .SourceRef .Name == "" {
427459 return sourcev1.GitRepository {}, fmt .Errorf ("no GitRepository reference given" )
@@ -449,18 +481,20 @@ func (r *HelmChartReconciler) getGitRepositoryWithArtifact(ctx context.Context,
449481// resetStatus returns a modified v1alpha1.HelmChart and a boolean indicating
450482// if the status field has been reset.
451483func (r * HelmChartReconciler ) resetStatus (chart sourcev1.HelmChart ) (sourcev1.HelmChart , bool ) {
484+ // The artifact does no longer exist
452485 if chart .GetArtifact () != nil && ! r .Storage .ArtifactExist (* chart .GetArtifact ()) {
453486 chart = sourcev1 .HelmChartProgressing (chart )
454487 chart .Status .Artifact = nil
455488 return chart , true
456489 }
490+ // The chart specification has changed
457491 if chart .Generation != chart .Status .ObservedGeneration {
458492 return sourcev1 .HelmChartProgressing (chart ), true
459493 }
460494 return chart , false
461495}
462496
463- // gc performs a garbage collection on all but current artifacts of
497+ // gc performs a garbage collection on all but the current artifact of
464498// the given chart.
465499func (r * HelmChartReconciler ) gc (chart sourcev1.HelmChart , all bool ) error {
466500 if all {
@@ -472,7 +506,8 @@ func (r *HelmChartReconciler) gc(chart sourcev1.HelmChart, all bool) error {
472506 return nil
473507}
474508
475- // event emits a Kubernetes event and forwards the event to notification controller if configured
509+ // event emits a Kubernetes event and forwards the event to notification
510+ // controller if configured.
476511func (r * HelmChartReconciler ) event (chart sourcev1.HelmChart , severity , msg string ) {
477512 if r .EventRecorder != nil {
478513 r .EventRecorder .Eventf (& chart , "Normal" , severity , msg )
0 commit comments