mirror of
https://github.com/containers/podman.git
synced 2025-05-20 16:47:39 +08:00
Introduce Podman machine reset
Podman machine reset is a new command that will "reset" your podman machine environment. Reset is defined as: * Stop and Remove all VMs * Remove the following directories: - configuration dir i.e. ~/.config/containers/podman/machine/qemu - data dir i.e. ~/.local/.share/containers/podman/machine/qemu When deleting, if errors are encountered, they will be batched and spit out at the end. Podman will try to proceed even in error in doing what it was told. Signed-off-by: Brent Baude <bbaude@redhat.com>
This commit is contained in:
98
cmd/podman/machine/reset.go
Normal file
98
cmd/podman/machine/reset.go
Normal file
@ -0,0 +1,98 @@
|
||||
//go:build amd64 || arm64
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/pkg/completion"
|
||||
"github.com/containers/podman/v5/cmd/podman/registry"
|
||||
"github.com/containers/podman/v5/cmd/podman/validate"
|
||||
"github.com/containers/podman/v5/pkg/machine"
|
||||
"github.com/containers/podman/v5/pkg/machine/shim"
|
||||
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
resetCmd = &cobra.Command{
|
||||
Use: "reset [options]",
|
||||
Short: "Remove all machines",
|
||||
Long: "Remove all machines, configurations, data, and cached images",
|
||||
PersistentPreRunE: machinePreRunE,
|
||||
RunE: reset,
|
||||
Args: validate.NoArgs,
|
||||
Example: `podman machine reset`,
|
||||
ValidArgsFunction: completion.AutocompleteNone,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
resetOptions machine.ResetOptions
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Command: resetCmd,
|
||||
Parent: machineCmd,
|
||||
})
|
||||
|
||||
flags := resetCmd.Flags()
|
||||
formatFlagName := "force"
|
||||
flags.BoolVarP(&resetOptions.Force, formatFlagName, "f", false, "Do not prompt before reset")
|
||||
}
|
||||
|
||||
func reset(_ *cobra.Command, _ []string) error {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
dirs, err := machine.GetMachineDirs(provider.VMType())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO we could consider saying we get a list of vms but can proceed
|
||||
// to just delete all local disk dirs, etc. Maybe a --proceed?
|
||||
mcs, err := vmconfigs.LoadMachinesInDir(dirs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !resetOptions.Force {
|
||||
vms := vmNamesFromMcs(mcs)
|
||||
resetConfirmationMessage(vms)
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print("\nAre you sure you want to continue? [y/N] ")
|
||||
answer, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.ToLower(answer)[0] != 'y' {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// resetErr can be nil or a multi-error
|
||||
return shim.Reset(dirs, provider, mcs)
|
||||
}
|
||||
|
||||
func resetConfirmationMessage(vms []string) {
|
||||
fmt.Println("Warning: this command will delete all existing Podman machines")
|
||||
fmt.Println("and all of the configuration and data directories for Podman machines")
|
||||
fmt.Printf("\nThe following machine(s) will be deleted:\n\n")
|
||||
for _, msg := range vms {
|
||||
fmt.Printf("%s\n", msg)
|
||||
}
|
||||
}
|
||||
|
||||
func vmNamesFromMcs(mcs map[string]*vmconfigs.MachineConfig) []string {
|
||||
keys := make([]string, 0, len(mcs))
|
||||
for k := range mcs {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
47
docs/source/markdown/podman-machine-reset.1.md
Normal file
47
docs/source/markdown/podman-machine-reset.1.md
Normal file
@ -0,0 +1,47 @@
|
||||
% podman-machine-reset 1
|
||||
|
||||
## NAME
|
||||
podman\-machine\-reset - Reset Podman machines and environment
|
||||
|
||||
## SYNOPSIS
|
||||
**podman machine reset** [*options*]
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Reset your Podman machine environment. This command stops any running machines
|
||||
and then removes them. Configuration and data files are then removed. Data files
|
||||
would include machine disk images and any previously pulled cache images. When
|
||||
this command is run, all of your Podman machines will have been deleted.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
#### **--force**, **-f**
|
||||
|
||||
Reset without confirmation.
|
||||
|
||||
#### **--help**
|
||||
|
||||
Print usage statement.
|
||||
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
```
|
||||
$ podman machine reset
|
||||
Warning: this command will delete all existing podman machines
|
||||
and all of the configuration and data directories for Podman machines
|
||||
|
||||
The following machine(s) will be deleted:
|
||||
|
||||
dev
|
||||
podman-machine-default
|
||||
|
||||
Are you sure you want to continue? [y/N] y
|
||||
$
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
**[podman(1)](podman.1.md)**, **[podman-machine(1)](podman-machine.1.md)**
|
||||
|
||||
## HISTORY
|
||||
Feb 2024, Originally compiled by Brent Baude<bbaude@redhat.com>
|
@ -22,21 +22,22 @@ environment variable while the machines are running can lead to unexpected behav
|
||||
|
||||
## SUBCOMMANDS
|
||||
|
||||
| Command | Man Page | Description |
|
||||
|---------|-----------------------------------------------------------|--------------------------------------|
|
||||
| info | [podman-machine-info(1)](podman-machine-info.1.md) | Display machine host info |
|
||||
| init | [podman-machine-init(1)](podman-machine-init.1.md) | Initialize a new virtual machine |
|
||||
| inspect | [podman-machine-inspect(1)](podman-machine-inspect.1.md) | Inspect one or more virtual machines |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| start | [podman-machine-start(1)](podman-machine-start.1.md) | Start a virtual machine |
|
||||
| stop | [podman-machine-stop(1)](podman-machine-stop.1.md) | Stop a virtual machine |
|
||||
| Command | Man Page | Description |
|
||||
|---------|----------------------------------------------------------|---------------------------------------|
|
||||
| info | [podman-machine-info(1)](podman-machine-info.1.md) | Display machine host info |
|
||||
| init | [podman-machine-init(1)](podman-machine-init.1.md) | Initialize a new virtual machine |
|
||||
| inspect | [podman-machine-inspect(1)](podman-machine-inspect.1.md) | Inspect one or more virtual machines |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| start | [podman-machine-start(1)](podman-machine-start.1.md) | Start a virtual machine |
|
||||
| stop | [podman-machine-stop(1)](podman-machine-stop.1.md) | Stop a virtual machine |
|
||||
|
||||
## SEE ALSO
|
||||
**[podman(1)](podman.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(1)](podman.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)**
|
||||
|
||||
## HISTORY
|
||||
March 2021, Originally compiled by Ashley Cui <acui@redhat.com>
|
||||
|
@ -83,6 +83,10 @@ type RemoveOptions struct {
|
||||
SaveIgnition bool
|
||||
}
|
||||
|
||||
type ResetOptions struct {
|
||||
Force bool
|
||||
}
|
||||
|
||||
type InspectOptions struct{}
|
||||
|
||||
// TODO This can be removed when WSL is refactored into podman 5
|
||||
|
25
pkg/machine/e2e/config_reset_test.go
Normal file
25
pkg/machine/e2e/config_reset_test.go
Normal file
@ -0,0 +1,25 @@
|
||||
package e2e_test
|
||||
|
||||
type resetMachine struct {
|
||||
/*
|
||||
-f, --force Stop and do not prompt before reseting
|
||||
*/
|
||||
|
||||
force bool
|
||||
|
||||
cmd []string
|
||||
}
|
||||
|
||||
func (i *resetMachine) buildCmd(m *machineTestBuilder) []string {
|
||||
cmd := []string{"machine", "reset"}
|
||||
if i.force {
|
||||
cmd = append(cmd, "--force")
|
||||
}
|
||||
i.cmd = cmd
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (i *resetMachine) withForce() *resetMachine {
|
||||
i.force = true
|
||||
return i
|
||||
}
|
88
pkg/machine/e2e/reset_test.go
Normal file
88
pkg/machine/e2e/reset_test.go
Normal file
@ -0,0 +1,88 @@
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
. "github.com/onsi/gomega/gexec"
|
||||
)
|
||||
|
||||
var _ = Describe("podman machine reset", func() {
|
||||
var (
|
||||
mb *machineTestBuilder
|
||||
testDir string
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
testDir, mb = setup()
|
||||
})
|
||||
AfterEach(func() {
|
||||
teardown(originalHomeDir, testDir, mb)
|
||||
})
|
||||
|
||||
It("starting from scratch should not error", func() {
|
||||
i := resetMachine{}
|
||||
session, err := mb.setCmd(i.withForce()).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(session).To(Exit(0))
|
||||
})
|
||||
|
||||
It("reset machine with one defined machine", func() {
|
||||
name := randomString()
|
||||
i := new(initMachine)
|
||||
session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath)).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(session).To(Exit(0))
|
||||
|
||||
ls := new(listMachine)
|
||||
beforeSession, err := mb.setCmd(ls.withNoHeading()).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(beforeSession).To(Exit(0))
|
||||
Expect(beforeSession.outputToStringSlice()).To(HaveLen(1))
|
||||
|
||||
reset := resetMachine{}
|
||||
resetSession, err := mb.setCmd(reset.withForce()).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resetSession).To(Exit(0))
|
||||
|
||||
afterSession, err := mb.setCmd(ls.withNoHeading()).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(afterSession).To(Exit(0))
|
||||
Expect(afterSession.outputToStringSlice()).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("reset with running machine and other machines idle ", func() {
|
||||
name := randomString()
|
||||
i := new(initMachine)
|
||||
session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath).withNow()).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(session).To(Exit(0))
|
||||
|
||||
ls := new(listMachine)
|
||||
beforeSession, err := mb.setCmd(ls.withNoHeading()).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(beforeSession).To(Exit(0))
|
||||
Expect(beforeSession.outputToStringSlice()).To(HaveLen(1))
|
||||
|
||||
name2 := randomString()
|
||||
i2 := new(initMachine)
|
||||
session2, err := mb.setName(name2).setCmd(i2.withImagePath(mb.imagePath)).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(session2).To(Exit(0))
|
||||
|
||||
beforeSession, err = mb.setCmd(ls.withNoHeading()).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(beforeSession).To(Exit(0))
|
||||
Expect(beforeSession.outputToStringSlice()).To(HaveLen(2))
|
||||
|
||||
reset := resetMachine{}
|
||||
resetSession, err := mb.setCmd(reset.withForce()).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resetSession).To(Exit(0))
|
||||
|
||||
afterSession, err := mb.setCmd(ls.withNoHeading()).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(afterSession).To(Exit(0))
|
||||
Expect(afterSession.outputToStringSlice()).To(BeEmpty())
|
||||
})
|
||||
|
||||
})
|
@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
@ -12,6 +13,8 @@ import (
|
||||
machineDefine "github.com/containers/podman/v5/pkg/machine/define"
|
||||
"github.com/containers/podman/v5/pkg/machine/ignition"
|
||||
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
|
||||
"github.com/containers/podman/v5/utils"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@ -446,3 +449,39 @@ func Start(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, _ *machineDefin
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Reset(dirs *machineDefine.MachineDirs, mp vmconfigs.VMProvider, mcs map[string]*vmconfigs.MachineConfig) error {
|
||||
var resetErrors *multierror.Error
|
||||
for _, mc := range mcs {
|
||||
err := Stop(mc, mp, dirs, true)
|
||||
if err != nil {
|
||||
resetErrors = multierror.Append(resetErrors, err)
|
||||
}
|
||||
_, genericRm, err := mc.Remove(false, false)
|
||||
if err != nil {
|
||||
resetErrors = multierror.Append(resetErrors, err)
|
||||
}
|
||||
_, providerRm, err := mp.Remove(mc)
|
||||
if err != nil {
|
||||
resetErrors = multierror.Append(resetErrors, err)
|
||||
}
|
||||
|
||||
if err := genericRm(); err != nil {
|
||||
resetErrors = multierror.Append(resetErrors, err)
|
||||
}
|
||||
if err := providerRm(); err != nil {
|
||||
resetErrors = multierror.Append(resetErrors, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the various directories
|
||||
// Note: we cannot delete the machine run dir blindly like this because
|
||||
// other things live there like the podman.socket and so forth.
|
||||
|
||||
// in linux this ~/.local/share/containers/podman/machine
|
||||
dataDirErr := utils.GuardedRemoveAll(filepath.Dir(dirs.DataDir.GetPath()))
|
||||
// in linux this ~/.config/containers/podman/machine
|
||||
confDirErr := utils.GuardedRemoveAll(filepath.Dir(dirs.ConfigDir.GetPath()))
|
||||
resetErrors = multierror.Append(resetErrors, confDirErr, dataDirErr)
|
||||
return resetErrors.ErrorOrNil()
|
||||
}
|
||||
|
Reference in New Issue
Block a user