diff --git a/pkg/action/install.go b/pkg/action/install.go index 933747d26..7c6ed474a 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -22,9 +22,12 @@ import ( "io/ioutil" "net/url" "os" + "os/signal" "path" "path/filepath" "strings" + "sync" + "syscall" "text/template" "time" @@ -66,6 +69,8 @@ const notesFileSuffix = "NOTES.txt" const defaultDirectoryPermission = 0755 +var installLock sync.Mutex + // Install performs an installation operation. type Install struct { cfg *Configuration @@ -331,11 +336,21 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. // not working. return rel, err } + rChan := make(chan resultMessage) + go i.performInstall(rChan, rel, toBeAdopted, resources) + go i.handleSignals(rChan, rel) + result := <-rChan + //start preformInstall go routine + return result.r, result.e +} + +func (i *Install) performInstall(c chan<- resultMessage, rel *release.Release, toBeAdopted kube.ResourceList, resources kube.ResourceList) { // pre-install hooks if !i.DisableHooks { if err := i.cfg.execHook(rel, release.HookPreInstall, i.Timeout); err != nil { - return i.failRelease(rel, fmt.Errorf("failed pre-install: %s", err)) + i.reportToRun(c, rel, fmt.Errorf("failed pre-install: %s", err)) + return } } @@ -344,29 +359,34 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. // to true, since that is basically an upgrade operation. if len(toBeAdopted) == 0 && len(resources) > 0 { if _, err := i.cfg.KubeClient.Create(resources); err != nil { - return i.failRelease(rel, err) + i.reportToRun(c, rel, err) + return } } else if len(resources) > 0 { if _, err := i.cfg.KubeClient.Update(toBeAdopted, resources, false); err != nil { - return i.failRelease(rel, err) + i.reportToRun(c, rel, err) + return } } if i.Wait { if i.WaitForJobs { if err := i.cfg.KubeClient.WaitWithJobs(resources, i.Timeout); err != nil { - return i.failRelease(rel, err) + i.reportToRun(c, rel, err) + return } } else { if err := i.cfg.KubeClient.Wait(resources, i.Timeout); err != nil { - return i.failRelease(rel, err) + i.reportToRun(c, rel, err) + return } } } if !i.DisableHooks { if err := i.cfg.execHook(rel, release.HookPostInstall, i.Timeout); err != nil { - return i.failRelease(rel, fmt.Errorf("failed post-install: %s", err)) + i.reportToRun(c, rel, fmt.Errorf("failed post-install: %s", err)) + return } } @@ -387,9 +407,26 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. i.cfg.Log("failed to record the release: %s", err) } - return rel, nil + i.reportToRun(c, rel, nil) +} +func (i *Install) handleSignals(c chan<- resultMessage, rel *release.Release) { + // Handle SIGINT + cSignal := make(chan os.Signal) + signal.Notify(cSignal, os.Interrupt, syscall.SIGTERM) + go func() { + <-cSignal + i.cfg.Log("SIGTERM or SIGINT received") + i.reportToRun(c, rel, fmt.Errorf("SIGTERM or SIGINT received, release failed")) + }() +} +func (i *Install) reportToRun(c chan<- resultMessage, rel *release.Release, err error) { + installLock.Lock() + if err != nil { + rel, err = i.failRelease(rel, err) + } + c <- resultMessage{r: rel, e: err} + installLock.Unlock() } - func (i *Install) failRelease(rel *release.Release, err error) (*release.Release, error) { rel.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", i.ReleaseName, err.Error())) if i.Atomic { diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 8ac0ee714..67bcd094f 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -40,7 +40,7 @@ import ( "helm.sh/helm/v3/pkg/storage/driver" ) -var mutex sync.Mutex +var upgradeLock sync.Mutex // Upgrade is the action for upgrading releases. // @@ -326,12 +326,12 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea } func (u *Upgrade) reportToPerformUpgrade(c chan<- resultMessage, rel *release.Release, created kube.ResourceList, err error) { - mutex.Lock() + upgradeLock.Lock() if err != nil { rel, err = u.failRelease(rel, created, err) } c <- resultMessage{r: rel, e: err} - mutex.Unlock() + upgradeLock.Unlock() } func (u *Upgrade) handleSignals(c chan<- resultMessage, upgradedRelease *release.Release) { // Handle SIGINT