mirror of
https://github.com/containers/podman.git
synced 2025-06-13 11:44:19 +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>
|
@ -22,21 +22,22 @@ environment variable while the machines are running can lead to unexpected behav
|
|||||||
|
|
||||||
## SUBCOMMANDS
|
## SUBCOMMANDS
|
||||||
|
|
||||||
| Command | Man Page | Description |
|
| Command | Man Page | Description |
|
||||||
|---------|-----------------------------------------------------------|--------------------------------------|
|
|---------|----------------------------------------------------------|---------------------------------------|
|
||||||
| info | [podman-machine-info(1)](podman-machine-info.1.md) | Display machine host info |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| reset | [podman-machine-reset(1)](podman-machine-reset.1.md) | Reset Podman machines and environment |
|
||||||
| set | [podman-machine-set(1)](podman-machine-set.1.md) | Set a virtual machine setting |
|
| rm | [podman-machine-rm(1)](podman-machine-rm.1.md) | Remove a virtual machine |
|
||||||
| ssh | [podman-machine-ssh(1)](podman-machine-ssh.1.md) | SSH into a virtual machine |
|
| set | [podman-machine-set(1)](podman-machine-set.1.md) | Set a virtual machine setting |
|
||||||
| start | [podman-machine-start(1)](podman-machine-start.1.md) | Start a virtual machine |
|
| ssh | [podman-machine-ssh(1)](podman-machine-ssh.1.md) | SSH into a virtual machine |
|
||||||
| stop | [podman-machine-stop(1)](podman-machine-stop.1.md) | Stop 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
|
## 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
|
## HISTORY
|
||||||
March 2021, Originally compiled by Ashley Cui <acui@redhat.com>
|
March 2021, Originally compiled by Ashley Cui <acui@redhat.com>
|
||||||
|
@ -83,6 +83,10 @@ type RemoveOptions struct {
|
|||||||
SaveIgnition bool
|
SaveIgnition bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ResetOptions struct {
|
||||||
|
Force bool
|
||||||
|
}
|
||||||
|
|
||||||
type InspectOptions struct{}
|
type InspectOptions struct{}
|
||||||
|
|
||||||
// TODO This can be removed when WSL is refactored into podman 5
|
// 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"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -12,6 +13,8 @@ import (
|
|||||||
machineDefine "github.com/containers/podman/v5/pkg/machine/define"
|
machineDefine "github.com/containers/podman/v5/pkg/machine/define"
|
||||||
"github.com/containers/podman/v5/pkg/machine/ignition"
|
"github.com/containers/podman/v5/pkg/machine/ignition"
|
||||||
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
|
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
|
||||||
|
"github.com/containers/podman/v5/utils"
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -446,3 +449,39 @@ func Start(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, _ *machineDefin
|
|||||||
|
|
||||||
return nil
|
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