Skip to content

Commit 7dd8fc5

Browse files
Merge pull request #21684 from baude/machinereset
Introduce Podman machine reset
2 parents e191f03 + 10d748f commit 7dd8fc5

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)