func (p *XPod) doStopPod(graceful int) error { var err error p.statusLock.Lock() if p.status != S_POD_RUNNING && p.status != S_POD_STARTING { err = fmt.Errorf("only alived pod could be stopped, current %d", p.status) } else { p.status = S_POD_STOPPING } p.statusLock.Unlock() if err != nil { p.Log(ERROR, err) return err } var errChan = make(chan error, 1) p.Log(INFO, "going to stop pod") go func(sb *hypervisor.Vm) { //lock all resource action of the pod, but don't block list/read query p.resourceLock.Lock() defer p.resourceLock.Unlock() //whatever the result of stop container, go on shutdown vm p.stopAllContainers(graceful) p.Log(INFO, "all container killed (or failed), now shutdown sandbox") result := sb.Shutdown() if result.IsSuccess() { p.Log(INFO, "pod is stopped") errChan <- nil return } err := fmt.Errorf("failed to shuting down: %s", result.Message()) p.Log(ERROR, err) errChan <- err }(p.sandbox) select { case err = <-errChan: if err != nil { p.Log(WARNING, "force quit sandbox due to %v", err) p.ForceQuit() } case <-utils.Timeout(graceful): p.Log(WARNING, "force quit sandbox due to timeout") p.ForceQuit() } return nil }
func (p *XPod) waitStopDone(timeout int, comments string) bool { select { case s, ok := <-p.stoppedChan: if ok { p.Log(DEBUG, "got stop msg and push it again: %s", comments) select { case p.stoppedChan <- s: default: } } p.Log(DEBUG, "wait stop done: %s", comments) return true case <-utils.Timeout(timeout): p.Log(DEBUG, "wait stop timeout: %s", comments) return false } }
func (p *XPod) stopContainers(cList []string, cMap map[string]bool, graceful int) (error, map[string]error) { type containerException struct { id string err error } p.Log(INFO, "begin stop containers %s", cList) resChan := p.sandbox.WaitProcess(true, cList, graceful) errChan := make(chan *containerException, 1) for _, cid := range cList { c, ok := p.containers[cid] if !ok { p.Log(WARNING, "no container %s to be stopped", cid) delete(cMap, cid) continue } if !c.IsRunning() { c.Log(DEBUG, "container state %v is not running(3), ignore during stop", c.CurrentState()) delete(cMap, cid) continue } go func(c *Container) { c.Log(DEBUG, "now, stop container") err := c.terminate() if err != nil { errChan <- &containerException{ id: c.Id(), err: err, } } }(c) } if len(cMap) > 0 && resChan == nil { err := fmt.Errorf("cannot wait containers %v", cList) p.Log(ERROR, err) return err, nil } timeout := utils.Timeout(graceful) errMap := map[string]error{} for len(cMap) > 0 { select { case ex, ok := <-resChan: if !ok { err := fmt.Errorf("chan broken while waiting containers: %#v", cMap) p.Log(WARNING, err) break //break the select } p.Log(DEBUG, "container %s stopped (%v)", ex.Id, ex.Code) if _, exist := errMap[ex.Id]; exist { //if it exited, ignore the exceptions delete(errMap, ex.Id) } delete(cMap, ex.Id) case ex := <-errChan: if cMap[ex.id] { //if not waited (maybe already exit, ignore the exception) p.Log(WARNING, "fail during killing container %s: %v", ex.id, ex.err) errMap[ex.id] = ex.err delete(cMap, ex.id) } case <-timeout: err := fmt.Errorf("timeout while waiting containers: %#v of [%v]", cMap, cList) p.Log(ERROR, err) return err, errMap } } p.Log(INFO, "complete stop containers %s", cList) return nil, errMap }