Skip to content

Commit 4c84612

Browse files
AlexsJonesclaude
andcommitted
fix(install): recover from failed releases and simplify ns creation
Previously, if a Helm install failed mid-flight the release was left in a non-deployed state (failed, pending-install, etc.) and subsequent `sympozium install` runs would wedge: upgrade errors with "has no deployed releases" and the install path refused to run. Detect non-deployed prior releases, uninstall them, then do a fresh install. Also drop the fragile kubectlQuiet namespace probe and always set CreateNamespace=true — safe now that the chart's own Namespace template is disabled via buildHelmValues. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e0aae1c commit 4c84612

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed

cmd/sympozium/main.go

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"helm.sh/helm/v3/pkg/action"
3030
"helm.sh/helm/v3/pkg/chart"
3131
helmcli "helm.sh/helm/v3/pkg/cli"
32+
"helm.sh/helm/v3/pkg/release"
3233
"helm.sh/helm/v3/pkg/strvals"
3334

3435
corev1 "k8s.io/api/core/v1"
@@ -1339,22 +1340,42 @@ func runInstall(imageTag string, setValues []string) error {
13391340
return err
13401341
}
13411342

1342-
// Check if a release already exists.
1343+
// Check if a release already exists and in what state.
13431344
histClient := action.NewHistory(cfg)
13441345
histClient.Max = 1
1345-
_, err = histClient.Run(helmReleaseName)
1346+
history, histErr := histClient.Run(helmReleaseName)
1347+
1348+
// A release is recoverable-by-install if history is missing, or if the
1349+
// most recent revision is in a non-deployed state (failed, pending-*,
1350+
// uninstalled). In those cases, upgrade will error with "has no deployed
1351+
// releases", so we uninstall and reinstall to recover cleanly.
1352+
needsFreshInstall := histErr != nil
1353+
if !needsFreshInstall && len(history) > 0 {
1354+
switch history[len(history)-1].Info.Status {
1355+
case release.StatusDeployed, release.StatusSuperseded:
1356+
// Healthy — upgrade path.
1357+
default:
1358+
fmt.Printf(" Found previous release in %q state, cleaning up...\n", history[len(history)-1].Info.Status)
1359+
uninstall := action.NewUninstall(cfg)
1360+
uninstall.Wait = true
1361+
uninstall.Timeout = 2 * time.Minute
1362+
if _, err := uninstall.Run(helmReleaseName); err != nil {
1363+
return fmt.Errorf("cleaning up failed release: %w", err)
1364+
}
1365+
needsFreshInstall = true
1366+
}
1367+
}
13461368

1347-
if err != nil {
1348-
// No existing release — fresh install.
1369+
if needsFreshInstall {
13491370
fmt.Println(" Running Helm install...")
13501371
install := action.NewInstall(cfg)
13511372
install.ReleaseName = helmReleaseName
13521373
install.Namespace = helmNamespace
1353-
// Only ask Helm to create the namespace if it doesn't already exist.
1354-
// Helm v3.20 wraps the namespace-create error in a multierror, which
1355-
// defeats its own IsAlreadyExists check and makes the install fail
1356-
// when the namespace was created by a previous partial install.
1357-
install.CreateNamespace = kubectlQuiet("get", "namespace", helmNamespace) != nil
1374+
// Safe to always request namespace creation: Helm treats an existing
1375+
// namespace as a no-op, and the chart's own Namespace template is
1376+
// disabled via buildHelmValues (createNamespace=false), so there is
1377+
// no collision.
1378+
install.CreateNamespace = true
13581379
install.SkipCRDs = true // We applied CRDs above.
13591380
install.Wait = false // Don't block — cert-manager certificate may need time.
13601381
install.Timeout = 5 * time.Minute
@@ -1363,7 +1384,7 @@ func runInstall(imageTag string, setValues []string) error {
13631384
return fmt.Errorf("helm install: %w", err)
13641385
}
13651386
} else {
1366-
// Existing release — upgrade.
1387+
// Existing deployed release — upgrade.
13671388
fmt.Println(" Running Helm upgrade...")
13681389
upgrade := action.NewUpgrade(cfg)
13691390
upgrade.Namespace = helmNamespace

0 commit comments

Comments
 (0)