// terminate the passed-in slice of hosts. returns any errors that occur // terminating the hosts func terminateHosts(hosts []host.Host, settings *evergreen.Settings, reason string) []error { errChan := make(chan error) for _, h := range hosts { evergreen.Logger.Logf(slogger.INFO, "Terminating host %v", h.Id) // terminate the host in a goroutine, passing the host in as a parameter // so that the variable isn't reused for subsequent iterations go func(hostToTerminate host.Host) { errChan <- func() error { event.LogMonitorOperation(hostToTerminate.Id, reason) err := util.RunFunctionWithTimeout(func() error { return terminateHost(&hostToTerminate, settings) }, 12*time.Minute) if err != nil { if err == util.ErrTimedOut { return fmt.Errorf("timeout terminating host %v", hostToTerminate.Id) } return fmt.Errorf("error terminating host %v: %v", hostToTerminate.Id, err) } evergreen.Logger.Logf(slogger.INFO, "Successfully terminated host %v", hostToTerminate.Id) return nil }() }(h) } var errors []error for range hosts { if err := <-errChan; err != nil { errors = append(errors, err) } } return errors }
// terminate the passed-in slice of hosts. returns any errors that occur // terminating the hosts func terminateHosts(hosts []host.Host, settings *evergreen.Settings, reason string) []error { // used to store any errors that occur var errors []error // for terminating the different hosts in parallel waitGroup := &sync.WaitGroup{} // to ensure thread-safe appending to the errors errsLock := &sync.Mutex{} for _, h := range hosts { evergreen.Logger.Logf(slogger.INFO, "Terminating host %v...", h.Id) waitGroup.Add(1) // terminate the host in a goroutine. pass the host in as a parameter // so that the variable isn't reused for subsequent iterations go func(hostToTerminate host.Host) { defer waitGroup.Done() // Log that the host was flagged, and why event.LogMonitorOperation(hostToTerminate.Id, reason) // wrapper function to terminate the host terminateFunc := func() error { return terminateHost(&hostToTerminate, settings) } // run the function with a timeout err := util.RunFunctionWithTimeout(terminateFunc, 10*time.Second) if err == util.ErrTimedOut { errsLock.Lock() errors = append(errors, fmt.Errorf("timeout terminating host %v", hostToTerminate.Id)) errsLock.Unlock() } else if err != nil { errsLock.Lock() errors = append(errors, fmt.Errorf("error terminating host: %v", err)) errsLock.Unlock() } else { evergreen.Logger.Logf(slogger.INFO, "Successfully terminated host %v", hostToTerminate.Id) } }(h) } // make sure all terminations finish waitGroup.Wait() return errors }