mirror of
https://github.com/containers/podman.git
synced 2025-06-20 00:51:16 +08:00
Merge pull request #12835 from baude/issue12815
Wait for podman stop to complete
This commit is contained in:
@ -29,6 +29,15 @@ type InitOptions struct {
|
|||||||
ReExec bool
|
ReExec bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QemuMachineStatus = string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Running indicates the qemu vm is running
|
||||||
|
Running QemuMachineStatus = "running"
|
||||||
|
// Stopped indicates the vm has stopped
|
||||||
|
Stopped QemuMachineStatus = "stopped"
|
||||||
|
)
|
||||||
|
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
NewMachine(opts InitOptions) (VM, error)
|
NewMachine(opts InitOptions) (VM, error)
|
||||||
LoadVMByName(name string) (VM, error)
|
LoadVMByName(name string) (VM, error)
|
||||||
|
@ -386,8 +386,16 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(v.Mounts) > 0 {
|
if len(v.Mounts) > 0 {
|
||||||
for !v.isRunning() || !v.isListening() {
|
running, err := v.isRunning()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for running || !v.isListening() {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
running, err = v.isRunning()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, mount := range v.Mounts {
|
for _, mount := range v.Mounts {
|
||||||
@ -416,8 +424,48 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *MachineVM) checkStatus(monitor *qmp.SocketMonitor) (machine.QemuMachineStatus, error) {
|
||||||
|
// this is the format returned from the monitor
|
||||||
|
// {"return": {"status": "running", "singlestep": false, "running": true}}
|
||||||
|
|
||||||
|
type statusDetails struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Step bool `json:"singlestep"`
|
||||||
|
Running bool `json:"running"`
|
||||||
|
}
|
||||||
|
type statusResponse struct {
|
||||||
|
Response statusDetails `json:"return"`
|
||||||
|
}
|
||||||
|
var response statusResponse
|
||||||
|
|
||||||
|
checkCommand := struct {
|
||||||
|
Execute string `json:"execute"`
|
||||||
|
}{
|
||||||
|
Execute: "query-status",
|
||||||
|
}
|
||||||
|
input, err := json.Marshal(checkCommand)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
b, err := monitor.Run(input)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Cause(err) == os.ErrNotExist {
|
||||||
|
return machine.Stopped, nil
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(b, &response); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if response.Response.Status == machine.Running {
|
||||||
|
return machine.Running, nil
|
||||||
|
}
|
||||||
|
return machine.Stopped, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Stop uses the qmp monitor to call a system_powerdown
|
// Stop uses the qmp monitor to call a system_powerdown
|
||||||
func (v *MachineVM) Stop(name string, _ machine.StopOptions) error {
|
func (v *MachineVM) Stop(name string, _ machine.StopOptions) error {
|
||||||
|
var disconnected bool
|
||||||
// check if the qmp socket is there. if not, qemu instance is gone
|
// check if the qmp socket is there. if not, qemu instance is gone
|
||||||
if _, err := os.Stat(v.QMPMonitor.Address); os.IsNotExist(err) {
|
if _, err := os.Stat(v.QMPMonitor.Address); os.IsNotExist(err) {
|
||||||
// Right now it is NOT an error to stop a stopped machine
|
// Right now it is NOT an error to stop a stopped machine
|
||||||
@ -442,19 +490,22 @@ func (v *MachineVM) Stop(name string, _ machine.StopOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := qmpMonitor.Disconnect(); err != nil {
|
if !disconnected {
|
||||||
logrus.Error(err)
|
if err := qmpMonitor.Disconnect(); err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if _, err = qmpMonitor.Run(input); err != nil {
|
if _, err = qmpMonitor.Run(input); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
qemuSocketFile, pidFile, err := v.getSocketandPid()
|
qemuSocketFile, pidFile, err := v.getSocketandPid()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(pidFile); os.IsNotExist(err) {
|
if _, err := os.Stat(pidFile); os.IsNotExist(err) {
|
||||||
logrus.Info(err)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pidString, err := ioutil.ReadFile(pidFile)
|
pidString, err := ioutil.ReadFile(pidFile)
|
||||||
@ -483,6 +534,24 @@ func (v *MachineVM) Stop(name string, _ machine.StopOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := qmpMonitor.Disconnect(); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnected = true
|
||||||
|
waitInternal := 250 * time.Millisecond
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
running, err := v.isRunning()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !running {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(waitInternal)
|
||||||
|
waitInternal = waitInternal * 2
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,7 +588,11 @@ func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, fun
|
|||||||
)
|
)
|
||||||
|
|
||||||
// cannot remove a running vm
|
// cannot remove a running vm
|
||||||
if v.isRunning() {
|
running, err := v.isRunning()
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
if running {
|
||||||
return "", nil, errors.Errorf("running vm %q cannot be destroyed", v.Name)
|
return "", nil, errors.Errorf("running vm %q cannot be destroyed", v.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,16 +651,33 @@ func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, fun
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *MachineVM) isRunning() bool {
|
func (v *MachineVM) isRunning() (bool, error) {
|
||||||
// Check if qmp socket path exists
|
// Check if qmp socket path exists
|
||||||
if _, err := os.Stat(v.QMPMonitor.Address); os.IsNotExist(err) {
|
if _, err := os.Stat(v.QMPMonitor.Address); os.IsNotExist(err) {
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
// Check if we can dial it
|
// Check if we can dial it
|
||||||
if _, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address, v.QMPMonitor.Timeout); err != nil {
|
monitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address, v.QMPMonitor.Timeout)
|
||||||
return false
|
if err != nil {
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
return true
|
if err := monitor.Connect(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := monitor.Disconnect(); err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// If there is a monitor, lets see if we can query state
|
||||||
|
state, err := v.checkStatus(monitor)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if state == machine.Running {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *MachineVM) isListening() bool {
|
func (v *MachineVM) isListening() bool {
|
||||||
@ -603,7 +693,11 @@ func (v *MachineVM) isListening() bool {
|
|||||||
// SSH opens an interactive SSH session to the vm specified.
|
// SSH opens an interactive SSH session to the vm specified.
|
||||||
// Added ssh function to VM interface: pkg/machine/config/go : line 58
|
// Added ssh function to VM interface: pkg/machine/config/go : line 58
|
||||||
func (v *MachineVM) SSH(name string, opts machine.SSHOptions) error {
|
func (v *MachineVM) SSH(name string, opts machine.SSHOptions) error {
|
||||||
if !v.isRunning() {
|
running, err := v.isRunning()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !running {
|
||||||
return errors.Errorf("vm %q is not running.", v.Name)
|
return errors.Errorf("vm %q is not running.", v.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -710,7 +804,11 @@ func GetVMInfos() ([]*machine.ListResponse, error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
listEntry.LastUp = fi.ModTime()
|
listEntry.LastUp = fi.ModTime()
|
||||||
if vm.isRunning() {
|
running, err := vm.isRunning()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if running {
|
||||||
listEntry.Running = true
|
listEntry.Running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user