Merge pull request #13996 from cdoern/machine

machine starting status
This commit is contained in:
OpenShift Merge Robot
2022-04-26 09:08:31 -04:00
committed by GitHub
6 changed files with 65 additions and 24 deletions

BIN
capture.pcap Normal file

Binary file not shown.

View File

@ -59,7 +59,7 @@ func inspect(cmd *cobra.Command, args []string) error {
errs = append(errs, err) errs = append(errs, err)
continue continue
} }
state, err := vm.State() state, err := vm.State(false)
if err != nil { if err != nil {
errs = append(errs, err) errs = append(errs, err)
continue continue

View File

@ -121,7 +121,7 @@ type VM interface {
Set(name string, opts SetOptions) error Set(name string, opts SetOptions) error
SSH(name string, opts SSHOptions) error SSH(name string, opts SSHOptions) error
Start(name string, opts StartOptions) error Start(name string, opts StartOptions) error
State() (Status, error) State(bypass bool) (Status, error)
Stop(name string, opts StopOptions) error Stop(name string, opts StopOptions) error
} }

View File

@ -86,6 +86,12 @@ type MachineVM struct {
ResourceConfig ResourceConfig
// SSHConfig for accessing the remote vm // SSHConfig for accessing the remote vm
SSHConfig SSHConfig
// Starting tells us whether the machine is running or if we have just dialed it to start it
Starting bool
// Created contains the original created time instead of querying the file mod time
Created time.Time
// LastUp contains the last recorded uptime
LastUp time.Time
} }
// ImageConfig describes the bootable image for the VM // ImageConfig describes the bootable image for the VM

View File

@ -94,6 +94,8 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
vm.Memory = opts.Memory vm.Memory = opts.Memory
vm.DiskSize = opts.DiskSize vm.DiskSize = opts.DiskSize
vm.Created = time.Now()
// Find the qemu executable // Find the qemu executable
cfg, err := config.Default() cfg, err := config.Default()
if err != nil { if err != nil {
@ -436,7 +438,7 @@ func (v *MachineVM) Set(_ string, opts machine.SetOptions) error {
return nil return nil
} }
state, err := v.State() state, err := v.State(false)
if err != nil { if err != nil {
return err return err
} }
@ -477,6 +479,17 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
wait = time.Millisecond * 500 wait = time.Millisecond * 500
) )
v.Starting = true
if err := v.writeConfig(); err != nil {
return fmt.Errorf("writing JSON file: %w", err)
}
defer func() error {
v.Starting = false
if err := v.writeConfig(); err != nil {
return fmt.Errorf("writing JSON file: %w", err)
}
return nil
}()
if v.isIncompatible() { if v.isIncompatible() {
logrus.Errorf("machine %q is incompatible with this release of podman and needs to be recreated, starting for recovery only", v.Name) logrus.Errorf("machine %q is incompatible with this release of podman and needs to be recreated, starting for recovery only", v.Name)
} }
@ -498,6 +511,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
return err return err
} }
} }
// If the qemusocketpath exists and the vm is off/down, we should rm // If the qemusocketpath exists and the vm is off/down, we should rm
// it before the dial as to avoid a segv // it before the dial as to avoid a segv
if err := v.QMPMonitor.Address.Delete(); err != nil { if err := v.QMPMonitor.Address.Delete(); err != nil {
@ -589,14 +603,14 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
return err return err
} }
if len(v.Mounts) > 0 { if len(v.Mounts) > 0 {
state, err := v.State() state, err := v.State(true)
if err != nil { if err != nil {
return err return err
} }
listening := v.isListening() listening := v.isListening()
for state != machine.Running || !listening { for state != machine.Running || !listening {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
state, err = v.State() state, err = v.State(true)
if err != nil { if err != nil {
return err return err
} }
@ -638,7 +652,6 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
} }
v.waitAPIAndPrintInfo(forwardState, forwardSock) v.waitAPIAndPrintInfo(forwardState, forwardSock)
return nil return nil
} }
@ -647,9 +660,10 @@ func (v *MachineVM) checkStatus(monitor *qmp.SocketMonitor) (machine.Status, err
// {"return": {"status": "running", "singlestep": false, "running": true}} // {"return": {"status": "running", "singlestep": false, "running": true}}
type statusDetails struct { type statusDetails struct {
Status string `json:"status"` Status string `json:"status"`
Step bool `json:"singlestep"` Step bool `json:"singlestep"`
Running bool `json:"running"` Running bool `json:"running"`
Starting bool `json:"starting"`
} }
type statusResponse struct { type statusResponse struct {
Response statusDetails `json:"return"` Response statusDetails `json:"return"`
@ -735,6 +749,11 @@ func (v *MachineVM) Stop(_ string, _ machine.StopOptions) error {
if p == nil && err != nil { if p == nil && err != nil {
return err return err
} }
v.LastUp = time.Now()
if err := v.writeConfig(); err != nil { // keep track of last up
return err
}
// Kill the process // Kill the process
if err := p.Kill(); err != nil { if err := p.Kill(); err != nil {
return err return err
@ -756,7 +775,7 @@ func (v *MachineVM) Stop(_ string, _ machine.StopOptions) error {
disconnected = true disconnected = true
waitInternal := 250 * time.Millisecond waitInternal := 250 * time.Millisecond
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
state, err := v.State() state, err := v.State(false)
if err != nil { if err != nil {
return err return err
} }
@ -808,7 +827,7 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func()
) )
// cannot remove a running vm unless --force is used // cannot remove a running vm unless --force is used
state, err := v.State() state, err := v.State(false)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
@ -874,12 +893,19 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func()
}, nil }, nil
} }
func (v *MachineVM) State() (machine.Status, error) { func (v *MachineVM) State(bypass bool) (machine.Status, error) {
// Check if qmp socket path exists // Check if qmp socket path exists
if _, err := os.Stat(v.QMPMonitor.Address.GetPath()); os.IsNotExist(err) { if _, err := os.Stat(v.QMPMonitor.Address.GetPath()); os.IsNotExist(err) {
return "", nil return "", nil
} }
err := v.update()
if err != nil {
return "", err
}
// Check if we can dial it // Check if we can dial it
if v.Starting && !bypass {
return "", nil
}
monitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address.GetPath(), v.QMPMonitor.Timeout) monitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address.GetPath(), v.QMPMonitor.Timeout)
if err != nil { if err != nil {
// FIXME: this error should probably be returned // FIXME: this error should probably be returned
@ -910,7 +936,7 @@ 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(_ string, opts machine.SSHOptions) error { func (v *MachineVM) SSH(_ string, opts machine.SSHOptions) error {
state, err := v.State() state, err := v.State(true)
if err != nil { if err != nil {
return err return err
} }
@ -1024,20 +1050,29 @@ func getVMInfos() ([]*machine.ListResponse, error) {
listEntry.Port = vm.Port listEntry.Port = vm.Port
listEntry.RemoteUsername = vm.RemoteUsername listEntry.RemoteUsername = vm.RemoteUsername
listEntry.IdentityPath = vm.IdentityPath listEntry.IdentityPath = vm.IdentityPath
fi, err := os.Stat(fullPath) listEntry.CreatedAt = vm.Created
if err != nil {
return err
}
listEntry.CreatedAt = fi.ModTime()
fi, err = os.Stat(vm.getImageFile()) if listEntry.CreatedAt.IsZero() {
listEntry.CreatedAt = time.Now()
vm.Created = time.Now()
if err := vm.writeConfig(); err != nil {
return err
}
}
state, err := vm.State(false)
if err != nil { if err != nil {
return err return err
} }
listEntry.LastUp = fi.ModTime()
state, err := vm.State() if !vm.LastUp.IsZero() {
if err != nil { listEntry.LastUp = vm.LastUp
return err } else {
listEntry.LastUp = vm.Created
vm.Created = time.Now()
if err := vm.writeConfig(); err != nil {
return err
}
} }
if state == machine.Running { if state == machine.Running {
listEntry.Running = true listEntry.Running = true

View File

@ -1028,7 +1028,7 @@ func (v *MachineVM) Stop(name string, _ machine.StopOptions) error {
// TODO: We need to rename isRunning to State(); I do not have a // TODO: We need to rename isRunning to State(); I do not have a
// windows system to test this on. // windows system to test this on.
func (v *MachineVM) State() (machine.Status, error) { func (v *MachineVM) State(bypass bool) (machine.Status, error) {
return "", define.ErrNotImplemented return "", define.ErrNotImplemented
} }