mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-08-05 00:15:44 +00:00
Merge pull request #28687 from jaitjacob/add-podman-machine-restart-command
Add `podman machine restart` subcommand
This commit is contained in:
commit
e121ed6264
6 changed files with 244 additions and 18 deletions
67
cmd/podman/machine/restart.go
Normal file
67
cmd/podman/machine/restart.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//go:build amd64 || arm64
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"go.podman.io/podman/v6/cmd/podman/registry"
|
||||
"go.podman.io/podman/v6/libpod/events"
|
||||
"go.podman.io/podman/v6/pkg/machine"
|
||||
"go.podman.io/podman/v6/pkg/machine/shim"
|
||||
)
|
||||
|
||||
var (
|
||||
restartCmd = &cobra.Command{
|
||||
Use: "restart [options] [MACHINE]",
|
||||
Short: "Restart an existing machine",
|
||||
Long: "Restart a managed virtual machine",
|
||||
PersistentPreRunE: machinePreRunE,
|
||||
RunE: restart,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Example: `podman machine restart podman-machine-default`,
|
||||
ValidArgsFunction: AutocompleteMachine,
|
||||
}
|
||||
restartOpts = machine.StartOptions{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Command: restartCmd,
|
||||
Parent: machineCmd,
|
||||
})
|
||||
|
||||
flags := restartCmd.Flags()
|
||||
noInfoFlagName := "no-info"
|
||||
flags.BoolVar(&restartOpts.NoInfo, noInfoFlagName, false, "Suppress informational tips")
|
||||
|
||||
quietFlagName := "quiet"
|
||||
flags.BoolVarP(&restartOpts.Quiet, quietFlagName, "q", false, "Suppress machine restarting status output")
|
||||
}
|
||||
|
||||
func restart(_ *cobra.Command, args []string) error {
|
||||
restartOpts.NoInfo = restartOpts.Quiet || restartOpts.NoInfo
|
||||
vmName := defaultMachineName
|
||||
if len(args) > 0 && len(args[0]) > 0 {
|
||||
vmName = args[0]
|
||||
}
|
||||
|
||||
mc, vmProvider, err := shim.VMExists(vmName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !restartOpts.Quiet {
|
||||
fmt.Printf("Restarting machine %q\n", vmName)
|
||||
}
|
||||
|
||||
updateConnection := false
|
||||
if err := shim.StopThenStart(mc, vmProvider, false, restartOpts, &updateConnection); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Machine %q restarted successfully\n", vmName)
|
||||
|
||||
newMachineEvent(events.Restart, events.Event{Name: vmName})
|
||||
return nil
|
||||
}
|
||||
46
docs/source/markdown/podman-machine-restart.1.md
Normal file
46
docs/source/markdown/podman-machine-restart.1.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
% podman-machine-restart 1
|
||||
|
||||
## NAME
|
||||
podman\-machine\-restart - Restart a virtual machine
|
||||
|
||||
## SYNOPSIS
|
||||
**podman machine restart** [*options*] [*name*]
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Restarts a virtual machine for Podman.
|
||||
|
||||
The default machine name is `podman-machine-default`. If a machine name is not specified as an argument,
|
||||
then `podman-machine-default` will be restarted.
|
||||
|
||||
Stopping an already stopped virtual machine is not considered an error so running restart on a stopped
|
||||
virtual machine just starts it from a stopped state.
|
||||
|
||||
**podman machine restart** stops and then starts a Linux virtual machine where containers are run.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
#### **--help**
|
||||
|
||||
Print usage statement.
|
||||
|
||||
#### **--no-info**
|
||||
|
||||
Suppress informational tips.
|
||||
|
||||
#### **--quiet**, **-q**
|
||||
|
||||
Suppress machine restarting status output.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
Restart a podman machine named myvm.
|
||||
```
|
||||
$ podman machine restart myvm
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
**[podman(1)](podman.1.md)**, **[podman-machine(1)](podman-machine.1.md)**, **[podman-machine-start(1)](podman-machine-start.1.md)**, **[podman-machine-stop(1)](podman-machine-stop.1.md)**
|
||||
|
||||
## HISTORY
|
||||
May 2026, Originally compiled by Jait Jacob <jai8.jacob@gmail.com>
|
||||
|
|
@ -44,6 +44,7 @@ supported by platform. The asterisk denotes the default provider for the platfo
|
|||
| list | [podman-machine-list(1)](podman-machine-list.1.md) | List virtual machines |
|
||||
| os | [podman-machine-os(1)](podman-machine-os.1.md) | Manage a Podman virtual machine's OS |
|
||||
| reset | [podman-machine-reset(1)](podman-machine-reset.1.md) | Reset Podman machines and environment |
|
||||
| restart | [podman-machine-restart(1)](podman-machine-restart.1.md) | Restart a virtual machine |
|
||||
| rm | [podman-machine-rm(1)](podman-machine-rm.1.md) | Remove a virtual machine |
|
||||
| set | [podman-machine-set(1)](podman-machine-set.1.md) | Set a virtual machine setting |
|
||||
| ssh | [podman-machine-ssh(1)](podman-machine-ssh.1.md) | SSH into a virtual machine |
|
||||
|
|
@ -51,7 +52,7 @@ supported by platform. The asterisk denotes the default provider for the platfo
|
|||
| stop | [podman-machine-stop(1)](podman-machine-stop.1.md) | Stop a virtual machine |
|
||||
|
||||
## SEE ALSO
|
||||
**[podman(1)](podman.1.md)**, **[podman-machine-cp(1)](podman-machine-cp.1.md)**, **[podman-machine-info(1)](podman-machine-info.1.md)**, **[podman-machine-init(1)](podman-machine-init.1.md)**, **[podman-machine-list(1)](podman-machine-list.1.md)**, **[podman-machine-os(1)](podman-machine-os.1.md)**, **[podman-machine-rm(1)](podman-machine-rm.1.md)**, **[podman-machine-ssh(1)](podman-machine-ssh.1.md)**, **[podman-machine-start(1)](podman-machine-start.1.md)**, **[podman-machine-stop(1)](podman-machine-stop.1.md)**, **[podman-machine-inspect(1)](podman-machine-inspect.1.md)**, **[podman-machine-reset(1)](podman-machine-reset.1.md)**, **[containers.conf(5)](https://github.com/containers/container-libs/blob/main/common/docs/containers.conf.5.md)**
|
||||
**[podman(1)](podman.1.md)**, **[podman-machine-cp(1)](podman-machine-cp.1.md)**, **[podman-machine-info(1)](podman-machine-info.1.md)**, **[podman-machine-init(1)](podman-machine-init.1.md)**, **[podman-machine-list(1)](podman-machine-list.1.md)**, **[podman-machine-os(1)](podman-machine-os.1.md)**, **[podman-machine-rm(1)](podman-machine-rm.1.md)**, **[podman-machine-ssh(1)](podman-machine-ssh.1.md)**, **[podman-machine-start(1)](podman-machine-start.1.md)**, **[podman-machine-stop(1)](podman-machine-stop.1.md)**, **[podman-machine-inspect(1)](podman-machine-inspect.1.md)**, **[podman-machine-reset(1)](podman-machine-reset.1.md)**, **[podman-machine-restart(1)](podman-machine-restart.1.md)**, **[containers.conf(5)](https://github.com/containers/container-libs/blob/main/common/docs/containers.conf.5.md)**
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
|
|
|
|||
11
pkg/machine/e2e/config_restart_test.go
Normal file
11
pkg/machine/e2e/config_restart_test.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package e2e_test
|
||||
|
||||
type restartMachine struct{}
|
||||
|
||||
func (r restartMachine) buildCmd(m *machineTestBuilder) []string {
|
||||
cmd := []string{"machine", "restart"}
|
||||
if len(m.name) > 0 {
|
||||
cmd = append(cmd, m.name)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
66
pkg/machine/e2e/restart_test.go
Normal file
66
pkg/machine/e2e/restart_test.go
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
package e2e_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.podman.io/podman/v6/pkg/machine/define"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
. "github.com/onsi/gomega/gexec"
|
||||
)
|
||||
|
||||
var _ = Describe("podman machine restart", func() {
|
||||
It("should tell you when trying to restart a machine that doesn't exist", func() {
|
||||
r := restartMachine{}
|
||||
name := "aVMThatDoesntExist"
|
||||
session, err := mb.setName(name).setCmd(r).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(session).To(Exit(125))
|
||||
Expect(session.errorToString()).To(ContainSubstring("VM does not exist"))
|
||||
})
|
||||
|
||||
It("should restart a running machine", func() {
|
||||
name := randomString()
|
||||
i := new(initMachine)
|
||||
session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath).withNow().withVolume("")).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(session).To(Exit(0))
|
||||
|
||||
r := restartMachine{}
|
||||
restartSession, err := mb.setName(name).setCmd(r).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(restartSession).To(Exit(0))
|
||||
Expect(restartSession.outputToString()).To(ContainSubstring(fmt.Sprintf("Machine %q restarted successfully", name)))
|
||||
|
||||
inspect := new(inspectMachine)
|
||||
inspectSession, err := mb.setName(name).setCmd(inspect.withFormat("{{.State}}")).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(inspectSession).To(Exit(0))
|
||||
Expect(inspectSession.outputToString()).To(Equal(define.Running))
|
||||
})
|
||||
|
||||
It("should start a stopped machine", func() {
|
||||
name := randomString()
|
||||
i := new(initMachine)
|
||||
session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath).withVolume("")).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(session).To(Exit(0))
|
||||
|
||||
inspect := new(inspectMachine)
|
||||
inspectSession, err := mb.setName(name).setCmd(inspect.withFormat("{{.State}}")).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(inspectSession).To(Exit(0))
|
||||
Expect(inspectSession.outputToString()).To(Equal(define.Stopped))
|
||||
|
||||
r := restartMachine{}
|
||||
restartSession, err := mb.setName(name).setCmd(r).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(restartSession).To(Exit(0))
|
||||
|
||||
inspectSession, err = mb.setName(name).setCmd(inspect.withFormat("{{.State}}")).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(inspectSession).To(Exit(0))
|
||||
Expect(inspectSession.outputToString()).To(Equal(define.Running))
|
||||
})
|
||||
})
|
||||
|
|
@ -431,6 +431,39 @@ func Stop(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, hardStop bool) e
|
|||
return stopLocked(mc, mp, dirs, hardStop)
|
||||
}
|
||||
|
||||
// StopThenStart stops and starts the machine while holding its lock.
|
||||
func StopThenStart(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, hardStop bool, opts machine.StartOptions, updateSystemConn *bool) error {
|
||||
dirs, err := env.GetMachineDirs(mp.VMType())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mc.Lock()
|
||||
defer mc.Unlock()
|
||||
err = mc.Refresh()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("reload config: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = stopLocked(mc, mp, dirs, hardStop)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mc.Refresh()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("reload config: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
callbackFuncs := machine.CleanUp()
|
||||
defer callbackFuncs.CleanIfErr(&err)
|
||||
go callbackFuncs.CleanOnSignal(opts.Quiet)
|
||||
|
||||
err = startLocked(mc, mp, dirs, opts, updateSystemConn, &callbackFuncs)
|
||||
return err
|
||||
}
|
||||
|
||||
// stopLocked stops the machine and expects the caller to hold the machine's lock.
|
||||
func stopLocked(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, dirs *machineDefine.MachineDirs, hardStop bool) error {
|
||||
state, err := mp.State(mc, false)
|
||||
|
|
@ -476,17 +509,11 @@ func stopLocked(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, dirs *mach
|
|||
}
|
||||
|
||||
func Start(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, opts machine.StartOptions, updateSystemConn *bool) error {
|
||||
var (
|
||||
err error
|
||||
updateDefaultConnection bool
|
||||
)
|
||||
dirs, err := env.GetMachineDirs(mp.VMType())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defaultBackoff := 500 * time.Millisecond
|
||||
maxBackoffs := 6
|
||||
|
||||
// startup rollaback functions
|
||||
// called if an error occurs or if a
|
||||
// a termination signal is sent
|
||||
callbackFuncs := machine.CleanUp()
|
||||
defer callbackFuncs.CleanIfErr(&err)
|
||||
// The following goroutine will block waiting
|
||||
|
|
@ -494,11 +521,6 @@ func Start(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, opts machine.St
|
|||
// the routine is aborted when the main goroutine terminates.
|
||||
go callbackFuncs.CleanOnSignal(opts.Quiet)
|
||||
|
||||
dirs, err := env.GetMachineDirs(mp.VMType())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !opts.ReExec {
|
||||
mc.Lock()
|
||||
// Use sync.Once to ensure that `mc.Unlock()` is called
|
||||
|
|
@ -521,10 +543,23 @@ func Start(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, opts machine.St
|
|||
defer func() { _ = mcunlock() }()
|
||||
}
|
||||
|
||||
if err = mc.Refresh(); err != nil {
|
||||
return fmt.Errorf("reload config: %w", err)
|
||||
err = mc.Refresh()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("reload config: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = startLocked(mc, mp, dirs, opts, updateSystemConn, &callbackFuncs)
|
||||
return err
|
||||
}
|
||||
|
||||
// startLocked starts the machine and expects the caller to hold the machine's lock.
|
||||
func startLocked(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, dirs *machineDefine.MachineDirs, opts machine.StartOptions, updateSystemConn *bool, callbackFuncs *machine.CleanupCallback) error {
|
||||
var updateDefaultConnection bool
|
||||
|
||||
defaultBackoff := 500 * time.Millisecond
|
||||
maxBackoffs := 6
|
||||
|
||||
connName := mc.Name
|
||||
if mc.HostUser.Rootful {
|
||||
connName += "-root"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue