Skip to content

Commit 10d748f

Browse files
committed
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>
1 parent fbb4d5d commit 10d748f

7 files changed

Lines changed: 315 additions & 13 deletions

File tree

cmd/podman/machine/reset.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//go:build amd64 || arm64
2+
3+
package machine
4+
5+
import (
6+
"bufio"
7+
"fmt"
8+
"os"
9+
"strings"
10+
11+
"github.com/containers/common/pkg/completion"
12+
"github.com/containers/podman/v5/cmd/podman/registry"
13+
"github.com/containers/podman/v5/cmd/podman/validate"
14+
"github.com/containers/podman/v5/pkg/machine"
15+
"github.com/containers/podman/v5/pkg/machine/shim"
16+
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
17+
"github.com/spf13/cobra"
18+
)
19+
20+
var (
21+
resetCmd = &cobra.Command{
22+
Use: "reset [options]",
23+
Short: "Remove all machines",
24+
Long: "Remove all machines, configurations, data, and cached images",
25+
PersistentPreRunE: machinePreRunE,
26+
RunE: reset,
27+
Args: validate.NoArgs,
28+
Example: `podman machine reset`,
29+
ValidArgsFunction: completion.AutocompleteNone,
30+
}
31+
)
32+
33+
var (
34+
resetOptions machine.ResetOptions
35+
)
36+
37+
func init() {
38+
registry.Commands = append(registry.Commands, registry.CliCommand{
39+
Command: resetCmd,
40+
Parent: machineCmd,
41+
})
42+
43+
flags := resetCmd.Flags()
44+
formatFlagName := "force"
45+
flags.BoolVarP(&resetOptions.Force, formatFlagName, "f", false, "Do not prompt before reset")
46+
}
47+
48+
func reset(_ *cobra.Command, _ []string) error {
49+
var (
50+
err error
51+
)
52+
53+
dirs, err := machine.GetMachineDirs(provider.VMType())
54+
if err != nil {
55+
return err
56+
}
57+
58+
// TODO we could consider saying we get a list of vms but can proceed
59+
// to just delete all local disk dirs, etc. Maybe a --proceed?
60+
mcs, err := vmconfigs.LoadMachinesInDir(dirs)
61+
if err != nil {
62+
return err
63+
}
64+
65+
if !resetOptions.Force {
66+
vms := vmNamesFromMcs(mcs)
67+
resetConfirmationMessage(vms)
68+
reader := bufio.NewReader(os.Stdin)
69+
fmt.Print("\nAre you sure you want to continue? [y/N] ")
70+
answer, err := reader.ReadString('\n')
71+
if err != nil {
72+
return err
73+
}
74+
if strings.ToLower(answer)[0] != 'y' {
75+
return nil
76+
}
77+
}
78+
79+
// resetErr can be nil or a multi-error
80+
return shim.Reset(dirs, provider, mcs)
81+
}
82+
83+
func resetConfirmationMessage(vms []string) {
84+
fmt.Println("Warning: this command will delete all existing Podman machines")
85+
fmt.Println("and all of the configuration and data directories for Podman machines")
86+
fmt.Printf("\nThe following machine(s) will be deleted:\n\n")
87+
for _, msg := range vms {
88+
fmt.Printf("%s\n", msg)
89+
}
90+
}
91+
92+
func vmNamesFromMcs(mcs map[string]*vmconfigs.MachineConfig) []string {
93+
keys := make([]string, 0, len(mcs))
94+
for k := range mcs {
95+
keys = append(keys, k)
96+
}
97+
return keys
98+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
% podman-machine-reset 1
2+
3+
## NAME
4+
podman\-machine\-reset - Reset Podman machines and environment
5+
6+
## SYNOPSIS
7+
**podman machine reset** [*options*]
8+
9+
## DESCRIPTION
10+
11+
Reset your Podman machine environment. This command stops any running machines
12+
and then removes them. Configuration and data files are then removed. Data files
13+
would include machine disk images and any previously pulled cache images. When
14+
this command is run, all of your Podman machines will have been deleted.
15+
16+
## OPTIONS
17+
18+
#### **--force**, **-f**
19+
20+
Reset without confirmation.
21+
22+
#### **--help**
23+
24+
Print usage statement.
25+
26+
27+
## EXAMPLES
28+
29+
```
30+
$ podman machine reset
31+
Warning: this command will delete all existing podman machines
32+
and all of the configuration and data directories for Podman machines
33+
34+
The following machine(s) will be deleted:
35+
36+
dev
37+
podman-machine-default
38+
39+
Are you sure you want to continue? [y/N] y
40+
$
41+
```
42+
43+
## SEE ALSO
44+
**[podman(1)](podman.1.md)**, **[podman-machine(1)](podman-machine.1.md)**
45+
46+
## HISTORY
47+
Feb 2024, Originally compiled by Brent Baude<bbaude@redhat.com>

docs/source/markdown/podman-machine.1.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,22 @@ environment variable while the machines are running can lead to unexpected behav
2222

2323
## SUBCOMMANDS
2424

25-
| Command | Man Page | Description |
26-
|---------|-----------------------------------------------------------|--------------------------------------|
27-
| info | [podman-machine-info(1)](podman-machine-info.1.md) | Display machine host info |
28-
| init | [podman-machine-init(1)](podman-machine-init.1.md) | Initialize a new virtual machine |
29-
| inspect | [podman-machine-inspect(1)](podman-machine-inspect.1.md) | Inspect one or more virtual machines |
30-
| list | [podman-machine-list(1)](podman-machine-list.1.md) | List virtual machines |
31-
| os | [podman-machine-os(1)](podman-machine-os.1.md) | Manage a Podman virtual machine's OS |
32-
| rm | [podman-machine-rm(1)](podman-machine-rm.1.md) | Remove a virtual machine |
33-
| set | [podman-machine-set(1)](podman-machine-set.1.md) | Set a virtual machine setting |
34-
| ssh | [podman-machine-ssh(1)](podman-machine-ssh.1.md) | SSH into a virtual machine |
35-
| start | [podman-machine-start(1)](podman-machine-start.1.md) | Start a virtual machine |
36-
| stop | [podman-machine-stop(1)](podman-machine-stop.1.md) | Stop a virtual machine |
25+
| Command | Man Page | Description |
26+
|---------|----------------------------------------------------------|---------------------------------------|
27+
| info | [podman-machine-info(1)](podman-machine-info.1.md) | Display machine host info |
28+
| init | [podman-machine-init(1)](podman-machine-init.1.md) | Initialize a new virtual machine |
29+
| inspect | [podman-machine-inspect(1)](podman-machine-inspect.1.md) | Inspect one or more virtual machines |
30+
| list | [podman-machine-list(1)](podman-machine-list.1.md) | List virtual machines |
31+
| os | [podman-machine-os(1)](podman-machine-os.1.md) | Manage a Podman virtual machine's OS |
32+
| reset | [podman-machine-reset(1)](podman-machine-reset.1.md) | Reset Podman machines and environment |
33+
| rm | [podman-machine-rm(1)](podman-machine-rm.1.md) | Remove a virtual machine |
34+
| set | [podman-machine-set(1)](podman-machine-set.1.md) | Set a virtual machine setting |
35+
| ssh | [podman-machine-ssh(1)](podman-machine-ssh.1.md) | SSH into a virtual machine |
36+
| start | [podman-machine-start(1)](podman-machine-start.1.md) | Start a virtual machine |
37+
| stop | [podman-machine-stop(1)](podman-machine-stop.1.md) | Stop a virtual machine |
3738

3839
## SEE ALSO
39-
**[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)**
40+
**[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)**
4041

4142
## HISTORY
4243
March 2021, Originally compiled by Ashley Cui <acui@redhat.com>

pkg/machine/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ type RemoveOptions struct {
8383
SaveIgnition bool
8484
}
8585

86+
type ResetOptions struct {
87+
Force bool
88+
}
89+
8690
type InspectOptions struct{}
8791

8892
// TODO This can be removed when WSL is refactored into podman 5
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package e2e_test
2+
3+
type resetMachine struct {
4+
/*
5+
-f, --force Stop and do not prompt before reseting
6+
*/
7+
8+
force bool
9+
10+
cmd []string
11+
}
12+
13+
func (i *resetMachine) buildCmd(m *machineTestBuilder) []string {
14+
cmd := []string{"machine", "reset"}
15+
if i.force {
16+
cmd = append(cmd, "--force")
17+
}
18+
i.cmd = cmd
19+
return cmd
20+
}
21+
22+
func (i *resetMachine) withForce() *resetMachine {
23+
i.force = true
24+
return i
25+
}

pkg/machine/e2e/reset_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package e2e_test
2+
3+
import (
4+
. "github.com/onsi/ginkgo/v2"
5+
. "github.com/onsi/gomega"
6+
. "github.com/onsi/gomega/gexec"
7+
)
8+
9+
var _ = Describe("podman machine reset", func() {
10+
var (
11+
mb *machineTestBuilder
12+
testDir string
13+
)
14+
15+
BeforeEach(func() {
16+
testDir, mb = setup()
17+
})
18+
AfterEach(func() {
19+
teardown(originalHomeDir, testDir, mb)
20+
})
21+
22+
It("starting from scratch should not error", func() {
23+
i := resetMachine{}
24+
session, err := mb.setCmd(i.withForce()).run()
25+
Expect(err).ToNot(HaveOccurred())
26+
Expect(session).To(Exit(0))
27+
})
28+
29+
It("reset machine with one defined machine", func() {
30+
name := randomString()
31+
i := new(initMachine)
32+
session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath)).run()
33+
Expect(err).ToNot(HaveOccurred())
34+
Expect(session).To(Exit(0))
35+
36+
ls := new(listMachine)
37+
beforeSession, err := mb.setCmd(ls.withNoHeading()).run()
38+
Expect(err).ToNot(HaveOccurred())
39+
Expect(beforeSession).To(Exit(0))
40+
Expect(beforeSession.outputToStringSlice()).To(HaveLen(1))
41+
42+
reset := resetMachine{}
43+
resetSession, err := mb.setCmd(reset.withForce()).run()
44+
Expect(err).ToNot(HaveOccurred())
45+
Expect(resetSession).To(Exit(0))
46+
47+
afterSession, err := mb.setCmd(ls.withNoHeading()).run()
48+
Expect(err).ToNot(HaveOccurred())
49+
Expect(afterSession).To(Exit(0))
50+
Expect(afterSession.outputToStringSlice()).To(BeEmpty())
51+
})
52+
53+
It("reset with running machine and other machines idle ", func() {
54+
name := randomString()
55+
i := new(initMachine)
56+
session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath).withNow()).run()
57+
Expect(err).ToNot(HaveOccurred())
58+
Expect(session).To(Exit(0))
59+
60+
ls := new(listMachine)
61+
beforeSession, err := mb.setCmd(ls.withNoHeading()).run()
62+
Expect(err).ToNot(HaveOccurred())
63+
Expect(beforeSession).To(Exit(0))
64+
Expect(beforeSession.outputToStringSlice()).To(HaveLen(1))
65+
66+
name2 := randomString()
67+
i2 := new(initMachine)
68+
session2, err := mb.setName(name2).setCmd(i2.withImagePath(mb.imagePath)).run()
69+
Expect(err).ToNot(HaveOccurred())
70+
Expect(session2).To(Exit(0))
71+
72+
beforeSession, err = mb.setCmd(ls.withNoHeading()).run()
73+
Expect(err).ToNot(HaveOccurred())
74+
Expect(beforeSession).To(Exit(0))
75+
Expect(beforeSession.outputToStringSlice()).To(HaveLen(2))
76+
77+
reset := resetMachine{}
78+
resetSession, err := mb.setCmd(reset.withForce()).run()
79+
Expect(err).ToNot(HaveOccurred())
80+
Expect(resetSession).To(Exit(0))
81+
82+
afterSession, err := mb.setCmd(ls.withNoHeading()).run()
83+
Expect(err).ToNot(HaveOccurred())
84+
Expect(afterSession).To(Exit(0))
85+
Expect(afterSession.outputToStringSlice()).To(BeEmpty())
86+
})
87+
88+
})

pkg/machine/shim/host.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55
"fmt"
66
"os"
7+
"path/filepath"
78
"runtime"
89
"time"
910

@@ -12,6 +13,8 @@ import (
1213
machineDefine "github.com/containers/podman/v5/pkg/machine/define"
1314
"github.com/containers/podman/v5/pkg/machine/ignition"
1415
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
16+
"github.com/containers/podman/v5/utils"
17+
"github.com/hashicorp/go-multierror"
1518
"github.com/sirupsen/logrus"
1619
)
1720

@@ -446,3 +449,39 @@ func Start(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, _ *machineDefin
446449

447450
return nil
448451
}
452+
453+
func Reset(dirs *machineDefine.MachineDirs, mp vmconfigs.VMProvider, mcs map[string]*vmconfigs.MachineConfig) error {
454+
var resetErrors *multierror.Error
455+
for _, mc := range mcs {
456+
err := Stop(mc, mp, dirs, true)
457+
if err != nil {
458+
resetErrors = multierror.Append(resetErrors, err)
459+
}
460+
_, genericRm, err := mc.Remove(false, false)
461+
if err != nil {
462+
resetErrors = multierror.Append(resetErrors, err)
463+
}
464+
_, providerRm, err := mp.Remove(mc)
465+
if err != nil {
466+
resetErrors = multierror.Append(resetErrors, err)
467+
}
468+
469+
if err := genericRm(); err != nil {
470+
resetErrors = multierror.Append(resetErrors, err)
471+
}
472+
if err := providerRm(); err != nil {
473+
resetErrors = multierror.Append(resetErrors, err)
474+
}
475+
}
476+
477+
// Delete the various directories
478+
// Note: we cannot delete the machine run dir blindly like this because
479+
// other things live there like the podman.socket and so forth.
480+
481+
// in linux this ~/.local/share/containers/podman/machine
482+
dataDirErr := utils.GuardedRemoveAll(filepath.Dir(dirs.DataDir.GetPath()))
483+
// in linux this ~/.config/containers/podman/machine
484+
confDirErr := utils.GuardedRemoveAll(filepath.Dir(dirs.ConfigDir.GetPath()))
485+
resetErrors = multierror.Append(resetErrors, confDirErr, dataDirErr)
486+
return resetErrors.ErrorOrNil()
487+
}

0 commit comments

Comments
 (0)