@@ -61,6 +61,9 @@ pub enum Error {
61
61
#[ snafu( display( "failed to install Helm release" ) ) ]
62
62
InstallRelease { source : InstallReleaseError } ,
63
63
64
+ #[ snafu( display( "failed to upgrade/install Helm release" ) ) ]
65
+ UpgradeRelease { source : InstallReleaseError } ,
66
+
64
67
#[ snafu( display( "failed to uninstall Helm release ({error})" ) ) ]
65
68
UninstallRelease { error : String } ,
66
69
}
@@ -248,6 +251,78 @@ pub fn install_release_from_repo_or_registry(
248
251
} )
249
252
}
250
253
254
+ /// Upgrades a Helm release from a repo or registry.
255
+ ///
256
+ /// This function expects the fully qualified Helm release name. In case of our
257
+ /// operators this is: `<PRODUCT_NAME>-operator`.
258
+ #[ instrument( skip( values_yaml) , fields( with_values = values_yaml. is_some( ) , indicatif. pb_show = true ) ) ]
259
+ pub fn upgrade_or_install_release_from_repo_or_registry (
260
+ release_name : & str ,
261
+ ChartVersion {
262
+ chart_source,
263
+ chart_name,
264
+ chart_version,
265
+ } : ChartVersion ,
266
+ values_yaml : Option < & str > ,
267
+ namespace : & str ,
268
+ suppress_output : bool ,
269
+ ) -> Result < InstallReleaseStatus , Error > {
270
+ // Ideally, each Helm invocation would spawn_blocking instead in/around helm_sys,
271
+ // but that requires a larger refactoring
272
+ block_in_place ( || {
273
+ debug ! ( "Install/Upgrade Helm release from repo" ) ;
274
+ Span :: current ( )
275
+ . pb_set_message ( format ! ( "Installing/Upgrading {chart_name} Helm chart" ) . as_str ( ) ) ;
276
+
277
+ if check_release_exists ( release_name, namespace) ? {
278
+ let release = get_release ( release_name, namespace) ?. ok_or ( Error :: InstallRelease {
279
+ source : InstallReleaseError :: NoSuchRelease {
280
+ name : release_name. to_owned ( ) ,
281
+ } ,
282
+ } ) ?;
283
+
284
+ let current_version = release. version ;
285
+
286
+ match chart_version {
287
+ Some ( chart_version) => {
288
+ if chart_version == current_version {
289
+ return Ok ( InstallReleaseStatus :: ReleaseAlreadyInstalledWithVersion {
290
+ requested_version : chart_version. to_string ( ) ,
291
+ release_name : release_name. to_string ( ) ,
292
+ current_version,
293
+ } ) ;
294
+ }
295
+ }
296
+ None => {
297
+ return Ok ( InstallReleaseStatus :: ReleaseAlreadyInstalledUnspecified {
298
+ release_name : release_name. to_string ( ) ,
299
+ current_version,
300
+ } ) ;
301
+ }
302
+ }
303
+ }
304
+
305
+ let full_chart_name = format ! ( "{chart_source}/{chart_name}" ) ;
306
+ let chart_version = chart_version. unwrap_or ( HELM_DEFAULT_CHART_VERSION ) ;
307
+
308
+ debug ! (
309
+ release_name,
310
+ chart_version, full_chart_name, "Installing Helm release"
311
+ ) ;
312
+
313
+ upgrade_release (
314
+ release_name,
315
+ & full_chart_name,
316
+ chart_version,
317
+ values_yaml,
318
+ namespace,
319
+ suppress_output,
320
+ ) ?;
321
+
322
+ Ok ( InstallReleaseStatus :: Installed ( release_name. to_string ( ) ) )
323
+ } )
324
+ }
325
+
251
326
/// Installs a Helm release.
252
327
///
253
328
/// This function expects the fully qualified Helm release name. In case of our
@@ -281,6 +356,47 @@ fn install_release(
281
356
Ok ( ( ) )
282
357
}
283
358
359
+ /// Upgrades a Helm release.
360
+ /// If a release with the specified `chart_name` does not already exist,
361
+ /// this function installs it instead.
362
+ ///
363
+ /// This function expects the fully qualified Helm release name. In case of our
364
+ /// operators this is: `<PRODUCT_NAME>-operator`.
365
+ #[ instrument( fields( with_values = values_yaml. is_some( ) ) ) ]
366
+ fn upgrade_release (
367
+ release_name : & str ,
368
+ chart_name : & str ,
369
+ chart_version : & str ,
370
+ values_yaml : Option < & str > ,
371
+ namespace : & str ,
372
+ suppress_output : bool ,
373
+ ) -> Result < ( ) , Error > {
374
+ // In Helm 3 the behavior of the `--force` option has changed
375
+ // It no longer deletes and re-installs a resource https://github.com/helm/helm/issues/7082#issuecomment-559558318
376
+ // Because of that, conflict errors might appear, which fail the upgrade, even if `helm upgrade --force` is used
377
+ // Therefore we uninstall the previous release (if present) and install the new one
378
+ uninstall_release ( release_name, namespace, suppress_output) ?;
379
+
380
+ let result = helm_sys:: install_helm_release (
381
+ release_name,
382
+ chart_name,
383
+ chart_version,
384
+ values_yaml. unwrap_or ( "" ) ,
385
+ namespace,
386
+ suppress_output,
387
+ ) ;
388
+
389
+ if let Some ( error) = helm_sys:: to_helm_error ( & result) {
390
+ error ! ( "Go wrapper function go_install_helm_release encountered an error: {error}" ) ;
391
+
392
+ return Err ( Error :: UpgradeRelease {
393
+ source : InstallReleaseError :: HelmWrapper { error } ,
394
+ } ) ;
395
+ }
396
+
397
+ Ok ( ( ) )
398
+ }
399
+
284
400
/// Uninstall a Helm release.
285
401
///
286
402
/// This function expects the fully qualified Helm release name. In case of our
0 commit comments