From 069eace84bc3c340829df94e7347e036f50aa61b Mon Sep 17 00:00:00 2001 From: Ashley Cui Date: Fri, 7 Jun 2024 14:06:24 -0400 Subject: [PATCH] Podman machine resets all providers Podman machine reset now removes and resets machines from all providers availabe on the platform. On windows, if the user is does not have admin privs, machine will only reset WSL, but will emit a warning that it is unable to remove hyperV machines without elevated privs. Signed-off-by: Ashley Cui --- cmd/podman/machine/reset.go | 43 +++++++---------- pkg/machine/provider/platform.go | 4 ++ pkg/machine/provider/platform_darwin.go | 7 +++ pkg/machine/provider/platform_windows.go | 12 +++++ pkg/machine/shim/host.go | 61 ++++++++++++++++-------- 5 files changed, 82 insertions(+), 45 deletions(-) diff --git a/cmd/podman/machine/reset.go b/cmd/podman/machine/reset.go index 8c2f01e19a..9b76f97a86 100644 --- a/cmd/podman/machine/reset.go +++ b/cmd/podman/machine/reset.go @@ -7,14 +7,14 @@ import ( "fmt" "os" "strings" + "text/tabwriter" "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/env" + provider2 "github.com/containers/podman/v5/pkg/machine/provider" "github.com/containers/podman/v5/pkg/machine/shim" - "github.com/containers/podman/v5/pkg/machine/vmconfigs" "github.com/spf13/cobra" ) @@ -23,7 +23,6 @@ var ( 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`, @@ -51,21 +50,19 @@ func reset(_ *cobra.Command, _ []string) error { err error ) - dirs, err := env.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) + providers, err := provider2.GetAll(resetOptions.Force) if err != nil { return err } if !resetOptions.Force { - vms := vmNamesFromMcs(mcs) - resetConfirmationMessage(vms) + listResponse, err := shim.List(providers, machine.ListOptions{}) + if err != nil { + return err + } + + resetConfirmationMessage(listResponse) + reader := bufio.NewReader(os.Stdin) fmt.Print("\nAre you sure you want to continue? [y/N] ") answer, err := reader.ReadString('\n') @@ -76,24 +73,18 @@ func reset(_ *cobra.Command, _ []string) error { return nil } } - - // resetErr can be nil or a multi-error - return shim.Reset(dirs, provider, mcs) + return shim.Reset(providers, resetOptions) } -func resetConfirmationMessage(vms []string) { +func resetConfirmationMessage(listResponse []*machine.ListResponse) { 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) - } -} + w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) + fmt.Fprintln(w, "NAME\tPROVIDER") -func vmNamesFromMcs(mcs map[string]*vmconfigs.MachineConfig) []string { - keys := make([]string, 0, len(mcs)) - for k := range mcs { - keys = append(keys, k) + for _, m := range listResponse { + fmt.Fprintf(w, "%s\t%s\n", m.Name, m.VMType) } - return keys + w.Flush() } diff --git a/pkg/machine/provider/platform.go b/pkg/machine/provider/platform.go index 2eb40072e1..40cf79053a 100644 --- a/pkg/machine/provider/platform.go +++ b/pkg/machine/provider/platform.go @@ -38,6 +38,10 @@ func Get() (vmconfigs.VMProvider, error) { } } +func GetAll(_ bool) ([]vmconfigs.VMProvider, error) { + return []vmconfigs.VMProvider{new(qemu.QEMUStubber)}, nil +} + // SupportedProviders returns the providers that are supported on the host operating system func SupportedProviders() []define.VMType { return []define.VMType{define.QemuVirt} diff --git a/pkg/machine/provider/platform_darwin.go b/pkg/machine/provider/platform_darwin.go index c868957b24..0c76421546 100644 --- a/pkg/machine/provider/platform_darwin.go +++ b/pkg/machine/provider/platform_darwin.go @@ -42,6 +42,13 @@ func Get() (vmconfigs.VMProvider, error) { } } +func GetAll(_ bool) ([]vmconfigs.VMProvider, error) { + return []vmconfigs.VMProvider{ + new(applehv.AppleHVStubber), + new(libkrun.LibKrunStubber), + }, nil +} + // SupportedProviders returns the providers that are supported on the host operating system func SupportedProviders() []define.VMType { supported := []define.VMType{define.AppleHvVirt} diff --git a/pkg/machine/provider/platform_windows.go b/pkg/machine/provider/platform_windows.go index f6a4577b24..772693669d 100644 --- a/pkg/machine/provider/platform_windows.go +++ b/pkg/machine/provider/platform_windows.go @@ -43,6 +43,18 @@ func Get() (vmconfigs.VMProvider, error) { } } +func GetAll(force bool) ([]vmconfigs.VMProvider, error) { + providers := []vmconfigs.VMProvider{ + new(wsl.WSLStubber), + } + if !wsl.HasAdminRights() && !force { + logrus.Warn("managing hyperv machines require admin authority.") + } else { + providers = append(providers, new(hyperv.HyperVStubber)) + } + return providers, nil +} + // SupportedProviders returns the providers that are supported on the host operating system func SupportedProviders() []define.VMType { return []define.VMType{define.HyperVVirt, define.WSLVirt} diff --git a/pkg/machine/shim/host.go b/pkg/machine/shim/host.go index a0d3a4252b..35ae43b991 100644 --- a/pkg/machine/shim/host.go +++ b/pkg/machine/shim/host.go @@ -636,38 +636,61 @@ func confirmationMessage(files []string) { } } -func Reset(dirs *machineDefine.MachineDirs, mp vmconfigs.VMProvider, mcs map[string]*vmconfigs.MachineConfig) error { +func Reset(mps []vmconfigs.VMProvider, opts machine.ResetOptions) 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) + removeDirs := []*machineDefine.MachineDirs{} + + for _, p := range mps { + d, err := env.GetMachineDirs(p.VMType()) if err != nil { resetErrors = multierror.Append(resetErrors, err) + continue } - _, providerRm, err := mp.Remove(mc) + mcs, err := vmconfigs.LoadMachinesInDir(d) if err != nil { resetErrors = multierror.Append(resetErrors, err) + continue } + removeDirs = append(removeDirs, d) - if err := genericRm(); err != nil { - resetErrors = multierror.Append(resetErrors, err) - } - if err := providerRm(); err != nil { - resetErrors = multierror.Append(resetErrors, err) + for _, mc := range mcs { + err := Stop(mc, p, d, 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 := p.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 + // We do this after all the provider rm's, since providers may still share the base machine dir. // 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) + for _, dir := range removeDirs { + // in linux this ~/.local/share/containers/podman/machine + dataDirErr := utils.GuardedRemoveAll(filepath.Dir(dir.DataDir.GetPath())) + if !errors.Is(dataDirErr, os.ErrNotExist) { + resetErrors = multierror.Append(resetErrors, dataDirErr) + } + // in linux this ~/.config/containers/podman/machine + confDirErr := utils.GuardedRemoveAll(filepath.Dir(dir.ConfigDir.GetPath())) + if !errors.Is(confDirErr, os.ErrNotExist) { + resetErrors = multierror.Append(resetErrors, confDirErr) + } + } return resetErrors.ErrorOrNil() }