mirror of
https://github.com/containers/podman.git
synced 2025-05-21 00:56:36 +08:00
machine: Add -all-providers flag to machine list
Podman machine list now supports a new option, --all-providers, which lists all machines from all providers. Signed-off-by: Ashley Cui <acui@redhat.com>
This commit is contained in:
@ -7,15 +7,18 @@ import (
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/common/pkg/completion"
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/common/pkg/report"
|
||||
"github.com/containers/podman/v5/cmd/podman/common"
|
||||
"github.com/containers/podman/v5/cmd/podman/registry"
|
||||
"github.com/containers/podman/v5/cmd/podman/validate"
|
||||
"github.com/containers/podman/v5/pkg/domain/entities"
|
||||
"github.com/containers/podman/v5/pkg/machine"
|
||||
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/docker/go-units"
|
||||
@ -24,11 +27,12 @@ import (
|
||||
|
||||
var (
|
||||
lsCmd = &cobra.Command{
|
||||
Use: "list [options]",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List machines",
|
||||
Long: "List managed virtual machines.",
|
||||
PersistentPreRunE: machinePreRunE,
|
||||
Use: "list [options]",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List machines",
|
||||
Long: "List managed virtual machines.",
|
||||
// do not use machinePreRunE, as that pre-sets the provider
|
||||
PersistentPreRunE: rootlessOnly,
|
||||
RunE: list,
|
||||
Args: validate.NoArgs,
|
||||
ValidArgsFunction: completion.AutocompleteNone,
|
||||
@ -40,9 +44,10 @@ var (
|
||||
)
|
||||
|
||||
type listFlagType struct {
|
||||
format string
|
||||
noHeading bool
|
||||
quiet bool
|
||||
format string
|
||||
noHeading bool
|
||||
quiet bool
|
||||
allProviders bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -57,6 +62,7 @@ func init() {
|
||||
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.ListReporter{}))
|
||||
flags.BoolVarP(&listFlag.noHeading, "noheading", "n", false, "Do not print headers")
|
||||
flags.BoolVarP(&listFlag.quiet, "quiet", "q", false, "Show only machine names")
|
||||
flags.BoolVar(&listFlag.allProviders, "all-providers", false, "Show machines from all providers")
|
||||
}
|
||||
|
||||
func list(cmd *cobra.Command, args []string) error {
|
||||
@ -64,8 +70,18 @@ func list(cmd *cobra.Command, args []string) error {
|
||||
opts machine.ListOptions
|
||||
err error
|
||||
)
|
||||
var providers []vmconfigs.VMProvider
|
||||
if listFlag.allProviders {
|
||||
providers = provider2.GetAll()
|
||||
} else {
|
||||
provider, err = provider2.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providers = []vmconfigs.VMProvider{provider}
|
||||
}
|
||||
|
||||
listResponse, err := shim.List([]vmconfigs.VMProvider{provider}, opts)
|
||||
listResponse, err := shim.List(providers, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -79,12 +95,8 @@ func list(cmd *cobra.Command, args []string) error {
|
||||
return listResponse[i].Running
|
||||
})
|
||||
|
||||
defaultCon := ""
|
||||
con, err := registry.PodmanConfig().ContainersConfDefaultsRO.GetConnection("", true)
|
||||
if err == nil {
|
||||
// ignore the error here we only want to know if we have a default connection to show it in list
|
||||
defaultCon = con.Name
|
||||
}
|
||||
// ignore the error here we only want to know if we have a default connection to show it in list
|
||||
defaultCon, _ := registry.PodmanConfig().ContainersConfDefaultsRO.GetConnection("", true)
|
||||
|
||||
if report.IsJSON(listFlag.format) {
|
||||
machineReporter := toMachineFormat(listResponse, defaultCon)
|
||||
@ -152,11 +164,16 @@ func streamName(imageStream string) string {
|
||||
return imageStream
|
||||
}
|
||||
|
||||
func toMachineFormat(vms []*machine.ListResponse, defaultCon string) []*entities.ListReporter {
|
||||
func toMachineFormat(vms []*machine.ListResponse, defaultCon *config.Connection) []*entities.ListReporter {
|
||||
machineResponses := make([]*entities.ListReporter, 0, len(vms))
|
||||
for _, vm := range vms {
|
||||
isDefault := false
|
||||
// check port, in case we somehow have machines with the same name in different providers
|
||||
if defaultCon != nil {
|
||||
isDefault = vm.Name == defaultCon.Name && strings.Contains(defaultCon.URI, strconv.Itoa((vm.Port)))
|
||||
}
|
||||
response := new(entities.ListReporter)
|
||||
response.Default = vm.Name == defaultCon
|
||||
response.Default = isDefault
|
||||
response.Name = vm.Name
|
||||
response.Running = vm.Running
|
||||
response.LastUp = strTime(vm.LastUp)
|
||||
@ -177,11 +194,16 @@ func toMachineFormat(vms []*machine.ListResponse, defaultCon string) []*entities
|
||||
return machineResponses
|
||||
}
|
||||
|
||||
func toHumanFormat(vms []*machine.ListResponse, defaultCon string) []*entities.ListReporter {
|
||||
func toHumanFormat(vms []*machine.ListResponse, defaultCon *config.Connection) []*entities.ListReporter {
|
||||
humanResponses := make([]*entities.ListReporter, 0, len(vms))
|
||||
for _, vm := range vms {
|
||||
response := new(entities.ListReporter)
|
||||
if vm.Name == defaultCon {
|
||||
isDefault := false
|
||||
// check port, in case we somehow have machines with the same name in different providers
|
||||
if defaultCon != nil {
|
||||
isDefault = vm.Name == defaultCon.Name && strings.Contains(defaultCon.URI, strconv.Itoa((vm.Port)))
|
||||
}
|
||||
if isDefault {
|
||||
response.Name = vm.Name + "*"
|
||||
response.Default = true
|
||||
} else {
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/containers/podman/v5/pkg/machine"
|
||||
provider2 "github.com/containers/podman/v5/pkg/machine/provider"
|
||||
"github.com/containers/podman/v5/pkg/machine/shim"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -50,10 +51,18 @@ func reset(_ *cobra.Command, _ []string) error {
|
||||
err error
|
||||
)
|
||||
|
||||
providers, err := provider2.GetAll(resetOptions.Force)
|
||||
providers := provider2.GetAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range providers {
|
||||
hasPerms := provider2.HasPermsForProvider(p.VMType())
|
||||
isInstalled, err := provider2.IsInstalled(p.VMType())
|
||||
if !hasPerms && (isInstalled || err != nil) && !resetOptions.Force {
|
||||
logrus.Warnf("Managing %s machines require admin authority.", p.VMType().String())
|
||||
logrus.Warnf("Continuing to reset may cause Podman to be unaware of remaining VMs in the VM manager.")
|
||||
}
|
||||
}
|
||||
|
||||
if !resetOptions.Force {
|
||||
listResponse, err := shim.List(providers, machine.ListOptions{})
|
||||
|
@ -26,6 +26,10 @@ environment variable while the machines are running can lead to unexpected behav
|
||||
|
||||
## OPTIONS
|
||||
|
||||
#### **--all-providers**
|
||||
|
||||
Show machines from all providers
|
||||
|
||||
#### **--format**=*format*
|
||||
|
||||
Change the default output format. This can be of a supported type like 'json'
|
||||
|
@ -1,3 +1,14 @@
|
||||
package e2e_test
|
||||
|
||||
import "github.com/containers/podman/v5/pkg/machine/define"
|
||||
|
||||
const podmanBinary = "../../../bin/darwin/podman"
|
||||
|
||||
func getOtherProvider() string {
|
||||
if isVmtype(define.AppleHvVirt) {
|
||||
return "libkrun"
|
||||
} else if isVmtype(define.LibKrun) {
|
||||
return "applehv"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
package e2e_test
|
||||
|
||||
const podmanBinary = "../../../bin/podman-remote"
|
||||
|
||||
func getOtherProvider() string {
|
||||
return ""
|
||||
}
|
||||
|
@ -7,9 +7,10 @@ type listMachine struct {
|
||||
-q, --quiet Show only machine names
|
||||
*/
|
||||
|
||||
format string
|
||||
noHeading bool
|
||||
quiet bool
|
||||
format string
|
||||
noHeading bool
|
||||
quiet bool
|
||||
allProviders bool
|
||||
|
||||
cmd []string
|
||||
}
|
||||
@ -25,6 +26,10 @@ func (i *listMachine) buildCmd(m *machineTestBuilder) []string {
|
||||
if i.quiet {
|
||||
cmd = append(cmd, "--quiet")
|
||||
}
|
||||
if i.allProviders {
|
||||
cmd = append(cmd, "--all-providers")
|
||||
}
|
||||
|
||||
i.cmd = cmd
|
||||
return cmd
|
||||
}
|
||||
@ -43,3 +48,8 @@ func (i *listMachine) withFormat(format string) *listMachine {
|
||||
i.format = format
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *listMachine) withAllProviders() *listMachine {
|
||||
i.allProviders = true
|
||||
return i
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
)
|
||||
|
||||
const podmanBinary = "../../../bin/windows/podman.exe"
|
||||
@ -23,3 +25,12 @@ func pgrep(n string) (string, error) {
|
||||
}
|
||||
return strOut, nil
|
||||
}
|
||||
|
||||
func getOtherProvider() string {
|
||||
if isVmtype(define.WSLVirt) {
|
||||
return "hyperv"
|
||||
} else if isVmtype(define.HyperVVirt) {
|
||||
return "wsl"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/podman/v5/pkg/domain/entities"
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
@ -182,6 +184,47 @@ var _ = Describe("podman machine list", func() {
|
||||
Expect(listSession).To(Exit(0))
|
||||
Expect(listSession.outputToString()).To(Equal("2GiB 11GiB"))
|
||||
})
|
||||
It("list machine from all providers", func() {
|
||||
skipIfVmtype(define.QemuVirt, "linux only has one provider")
|
||||
|
||||
// create machine on other provider
|
||||
currprovider := os.Getenv("CONTAINERS_MACHINE_PROVIDER")
|
||||
os.Setenv("CONTAINERS_MACHINE_PROVIDER", getOtherProvider())
|
||||
defer os.Setenv("CONTAINERS_MACHINE_PROVIDER", currprovider)
|
||||
|
||||
// this may take a long time - we're not pre-fetching this image
|
||||
othermach := new(initMachine)
|
||||
session, err := mb.setName("otherprovider").setCmd(othermach).run()
|
||||
// make sure to remove machine from other provider later
|
||||
defer func() {
|
||||
os.Setenv("CONTAINERS_MACHINE_PROVIDER", getOtherProvider())
|
||||
defer os.Setenv("CONTAINERS_MACHINE_PROVIDER", currprovider)
|
||||
rm := new(rmMachine)
|
||||
removed, err := mb.setName("otherprovider").setCmd(rm.withForce()).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(removed).To(Exit(0))
|
||||
}()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(session).To(Exit(0))
|
||||
|
||||
// change back to current provider
|
||||
os.Setenv("CONTAINERS_MACHINE_PROVIDER", currprovider)
|
||||
name := randomString()
|
||||
i := new(initMachine)
|
||||
session, err = mb.setName(name).setCmd(i.withImage(mb.imagePath)).run()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(session).To(Exit(0))
|
||||
|
||||
list := new(listMachine)
|
||||
listSession, err := mb.setCmd(list.withAllProviders().withFormat("{{.Name}}")).run()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(listSession).To(Exit(0))
|
||||
listNames := listSession.outputToStringSlice()
|
||||
stripAsterisk(listNames)
|
||||
Expect(listNames).To(HaveLen(2))
|
||||
Expect(slices.Contains(listNames, "otherprovider")).To(BeTrue())
|
||||
Expect(slices.Contains(listNames, name)).To(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
func stripAsterisk(sl []string) {
|
||||
|
@ -1,71 +1,20 @@
|
||||
//go:build !windows && !darwin
|
||||
|
||||
package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
"github.com/containers/podman/v5/pkg/machine/qemu"
|
||||
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func Get() (vmconfigs.VMProvider, error) {
|
||||
cfg, err := config.Default()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
provider := cfg.Machine.Provider
|
||||
if providerOverride, found := os.LookupEnv("CONTAINERS_MACHINE_PROVIDER"); found {
|
||||
provider = providerOverride
|
||||
}
|
||||
resolvedVMType, err := define.ParseVMType(provider, define.QemuVirt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logrus.Debugf("Using Podman machine with `%s` virtualization provider", resolvedVMType.String())
|
||||
switch resolvedVMType {
|
||||
case define.QemuVirt:
|
||||
return qemu.NewStubber()
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported virtualization provider: `%s`", resolvedVMType.String())
|
||||
}
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
// InstalledProviders returns the supported providers that are installed on the host
|
||||
func InstalledProviders() ([]define.VMType, error) {
|
||||
cfg, err := config.Default()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
installedTypes := []define.VMType{}
|
||||
providers := GetAll()
|
||||
for _, p := range providers {
|
||||
installed, err := IsInstalled(p.VMType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if installed {
|
||||
installedTypes = append(installedTypes, p.VMType())
|
||||
}
|
||||
}
|
||||
_, err = cfg.FindHelperBinary(qemu.QemuCommand, true)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return []define.VMType{}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []define.VMType{define.QemuVirt}, nil
|
||||
}
|
||||
|
||||
// HasPermsForProvider returns whether the host operating system has the proper permissions to use the given provider
|
||||
func HasPermsForProvider(provider define.VMType) bool {
|
||||
// there are no permissions required for QEMU
|
||||
return provider == define.QemuVirt
|
||||
return installedTypes, nil
|
||||
}
|
||||
|
@ -42,11 +42,11 @@ func Get() (vmconfigs.VMProvider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func GetAll(_ bool) ([]vmconfigs.VMProvider, error) {
|
||||
func GetAll() []vmconfigs.VMProvider {
|
||||
return []vmconfigs.VMProvider{
|
||||
new(applehv.AppleHVStubber),
|
||||
new(libkrun.LibKrunStubber),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SupportedProviders returns the providers that are supported on the host operating system
|
||||
@ -58,27 +58,23 @@ func SupportedProviders() []define.VMType {
|
||||
return supported
|
||||
}
|
||||
|
||||
// InstalledProviders returns the supported providers that are installed on the host
|
||||
func InstalledProviders() ([]define.VMType, error) {
|
||||
installed := []define.VMType{}
|
||||
|
||||
appleHvInstalled, err := appleHvInstalled()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func IsInstalled(provider define.VMType) (bool, error) {
|
||||
switch provider {
|
||||
case define.AppleHvVirt:
|
||||
ahv, err := appleHvInstalled()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return ahv, nil
|
||||
case define.LibKrun:
|
||||
lkr, err := libKrunInstalled()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return lkr, nil
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
if appleHvInstalled {
|
||||
installed = append(installed, define.AppleHvVirt)
|
||||
}
|
||||
|
||||
libKrunInstalled, err := libKrunInstalled()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if libKrunInstalled {
|
||||
installed = append(installed, define.LibKrun)
|
||||
}
|
||||
|
||||
return installed, nil
|
||||
}
|
||||
|
||||
func appleHvInstalled() (bool, error) {
|
||||
|
77
pkg/machine/provider/platform_unix.go
Normal file
77
pkg/machine/provider/platform_unix.go
Normal file
@ -0,0 +1,77 @@
|
||||
//go:build !windows && !darwin
|
||||
|
||||
package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
"github.com/containers/podman/v5/pkg/machine/qemu"
|
||||
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func Get() (vmconfigs.VMProvider, error) {
|
||||
cfg, err := config.Default()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
provider := cfg.Machine.Provider
|
||||
if providerOverride, found := os.LookupEnv("CONTAINERS_MACHINE_PROVIDER"); found {
|
||||
provider = providerOverride
|
||||
}
|
||||
resolvedVMType, err := define.ParseVMType(provider, define.QemuVirt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logrus.Debugf("Using Podman machine with `%s` virtualization provider", resolvedVMType.String())
|
||||
switch resolvedVMType {
|
||||
case define.QemuVirt:
|
||||
return qemu.NewStubber()
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported virtualization provider: `%s`", resolvedVMType.String())
|
||||
}
|
||||
}
|
||||
|
||||
func GetAll() []vmconfigs.VMProvider {
|
||||
return []vmconfigs.VMProvider{new(qemu.QEMUStubber)}
|
||||
}
|
||||
|
||||
// SupportedProviders returns the providers that are supported on the host operating system
|
||||
func SupportedProviders() []define.VMType {
|
||||
return []define.VMType{define.QemuVirt}
|
||||
}
|
||||
|
||||
func IsInstalled(provider define.VMType) (bool, error) {
|
||||
switch provider {
|
||||
case define.QemuVirt:
|
||||
cfg, err := config.Default()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if cfg == nil {
|
||||
return false, fmt.Errorf("error fetching getting default config")
|
||||
}
|
||||
_, err = cfg.FindHelperBinary(qemu.QemuCommand, true)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// HasPermsForProvider returns whether the host operating system has the proper permissions to use the given provider
|
||||
func HasPermsForProvider(provider define.VMType) bool {
|
||||
// there are no permissions required for QEMU
|
||||
return provider == define.QemuVirt
|
||||
}
|
@ -43,16 +43,11 @@ func Get() (vmconfigs.VMProvider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func GetAll(force bool) ([]vmconfigs.VMProvider, error) {
|
||||
providers := []vmconfigs.VMProvider{
|
||||
func GetAll() []vmconfigs.VMProvider {
|
||||
return []vmconfigs.VMProvider{
|
||||
new(wsl.WSLStubber),
|
||||
new(hyperv.HyperVStubber),
|
||||
}
|
||||
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
|
||||
@ -60,20 +55,22 @@ func SupportedProviders() []define.VMType {
|
||||
return []define.VMType{define.HyperVVirt, define.WSLVirt}
|
||||
}
|
||||
|
||||
// InstalledProviders returns the supported providers that are installed on the host
|
||||
func InstalledProviders() ([]define.VMType, error) {
|
||||
installed := []define.VMType{}
|
||||
if wutil.IsWSLInstalled() {
|
||||
installed = append(installed, define.WSLVirt)
|
||||
func IsInstalled(provider define.VMType) (bool, error) {
|
||||
switch provider {
|
||||
case define.WSLVirt:
|
||||
return wutil.IsWSLInstalled(), nil
|
||||
case define.HyperVVirt:
|
||||
service, err := hypervctl.NewLocalHyperVService()
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if service != nil {
|
||||
defer service.Close()
|
||||
}
|
||||
return false, nil
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
|
||||
service, err := hypervctl.NewLocalHyperVService()
|
||||
if err == nil {
|
||||
installed = append(installed, define.HyperVVirt)
|
||||
}
|
||||
service.Close()
|
||||
|
||||
return installed, nil
|
||||
}
|
||||
|
||||
// HasPermsForProvider returns whether the host operating system has the proper permissions to use the given provider
|
||||
|
Reference in New Issue
Block a user