mirror of
https://github.com/containers/podman.git
synced 2025-06-12 11:02:00 +08:00
Merge pull request #21684 from baude/machinereset
Introduce Podman machine reset
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>
|
@ -23,12 +23,13 @@ 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 |
|
||||
| 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 |
|
||||
@ -36,7 +37,7 @@ environment variable while the machines are running can lead to unexpected behav
|
||||
| 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