From 518eafaa348c7da8272c9a6ef7d697fff974acec Mon Sep 17 00:00:00 2001 From: Brent Baude Date: Wed, 22 Mar 2023 15:29:24 -0500 Subject: [PATCH] hyperv: lookup machine on local filesystem first when looking for a machine, look it up locally first to prevent accidental collision with non-podman machine vms. in the cast of `podman machine ls`, only list podman machines found by json files Enabled remove with force. [NO NEW TESTS NEEDED] Signed-off-by: Brent Baude --- go.mod | 2 +- go.sum | 4 +- pkg/machine/hyperv/config.go | 17 ++- pkg/machine/hyperv/machine.go | 44 ++++--- .../containers/libhvee/pkg/hypervctl/error.go | 44 ++++++- .../libhvee/pkg/hypervctl/memory_settings.go | 8 +- .../pkg/hypervctl/processor_settings.go | 8 +- .../libhvee/pkg/hypervctl/summary.go | 5 +- .../libhvee/pkg/hypervctl/system_settings.go | 2 +- .../pkg/hypervctl/system_settings_builder.go | 4 +- .../containers/libhvee/pkg/hypervctl/vm.go | 117 ++++++++++++++++-- .../containers/libhvee/pkg/hypervctl/vmm.go | 2 +- .../libhvee/pkg/wmiext/conversion.go | 13 +- .../containers/libhvee/pkg/wmiext/service.go | 14 +++ vendor/modules.txt | 2 +- 15 files changed, 232 insertions(+), 54 deletions(-) diff --git a/go.mod b/go.mod index 0e2e76f0cb..bb50df0a2e 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/containers/common v0.51.1-0.20230316131336-0be880eaeb02 github.com/containers/conmon v2.0.20+incompatible github.com/containers/image/v5 v5.24.3-0.20230314083015-0c6d07e02a9a - github.com/containers/libhvee v0.0.1 + github.com/containers/libhvee v0.0.2 github.com/containers/ocicrypt v1.1.7 github.com/containers/psgo v1.8.0 github.com/containers/storage v1.45.5-0.20230315220505-1c6287eea927 diff --git a/go.sum b/go.sum index 335b7e8756..504e8fc66f 100644 --- a/go.sum +++ b/go.sum @@ -253,8 +253,8 @@ github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6J github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.24.3-0.20230314083015-0c6d07e02a9a h1:2xIif78r5x2nmdb5uhjXBZuexiDAt1c/XIXFxFhfKSk= github.com/containers/image/v5 v5.24.3-0.20230314083015-0c6d07e02a9a/go.mod h1:9PM/hiCVTh6dt8Swi7eYKXKHIaPabHn8gtFV2YD44Mk= -github.com/containers/libhvee v0.0.1 h1:QpknIQ2VG54HLNoXb0ZXdmah8lw7EC2atD5pX7543pI= -github.com/containers/libhvee v0.0.1/go.mod h1:bV1MfbuXk/ZLWHiWZpm8aePOR6iJGD1q55guYhH4CnA= +github.com/containers/libhvee v0.0.2 h1:eWtbOvpT8bD9jvksMES2yXUmEpcE0zENWkci+bbP7U8= +github.com/containers/libhvee v0.0.2/go.mod h1:bV1MfbuXk/ZLWHiWZpm8aePOR6iJGD1q55guYhH4CnA= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= diff --git a/pkg/machine/hyperv/config.go b/pkg/machine/hyperv/config.go index 73ee154462..04430e545c 100644 --- a/pkg/machine/hyperv/config.go +++ b/pkg/machine/hyperv/config.go @@ -70,16 +70,16 @@ func (v Virtualization) IsValidVMName(name string) (bool, error) { } func (v Virtualization) List(opts machine.ListOptions) ([]*machine.ListResponse, error) { - var response []*machine.ListResponse - vmm := hypervctl.NewVirtualMachineManager() - vms, err := vmm.GetAll() + mms, err := v.loadFromLocalJson() if err != nil { return nil, err } - for _, vm := range vms { - m := &HyperVMachine{Name: vm.ElementName} - mm, err := m.loadFromFile() + var response []*machine.ListResponse + vmm := hypervctl.NewVirtualMachineManager() + + for _, mm := range mms { + vm, err := vmm.GetMachine(mm.Name) if err != nil { return nil, err } @@ -159,8 +159,7 @@ func (v Virtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) config := hypervctl.HardwareConfig{ CPUs: uint16(opts.CPUS), DiskPath: imagePath.GetPath(), - // TODO remove this and make real - DiskSize: 100, + DiskSize: opts.DiskSize, Memory: int32(opts.Memory), } @@ -251,7 +250,7 @@ func (v Virtualization) loadFromLocalJson() ([]*HyperVMachine, error) { if e != nil { return e } - if filepath.Ext(d.Name()) == "json" { + if filepath.Ext(d.Name()) == ".json" { jsonFiles = append(jsonFiles, input) } return nil diff --git a/pkg/machine/hyperv/machine.go b/pkg/machine/hyperv/machine.go index b99881171c..c7abce9608 100644 --- a/pkg/machine/hyperv/machine.go +++ b/pkg/machine/hyperv/machine.go @@ -8,7 +8,7 @@ import ( "encoding/json" "errors" "fmt" - "github.com/docker/go-units" + "io/fs" "net/url" "os" "path/filepath" @@ -18,6 +18,7 @@ import ( "github.com/containers/libhvee/pkg/hypervctl" "github.com/containers/podman/v4/pkg/machine" "github.com/containers/storage/pkg/homedir" + "github.com/docker/go-units" "github.com/sirupsen/logrus" ) @@ -237,11 +238,12 @@ func (m *HyperVMachine) Remove(_ string, opts machine.RemoveOptions) (string, fu } // In hyperv, they call running 'enabled' if vm.State() == hypervctl.Enabled { - // TODO Add for force - // Right now, the ole response from hyperv is segv'ing - // and until it comes back clean, force cannot be implemented - // because it will always fail. - return "", nil, hypervctl.ErrMachineStateInvalid + if !opts.Force { + return "", nil, hypervctl.ErrMachineStateInvalid + } + if err := vm.Stop(); err != nil { + return "", nil, err + } } // Collect all the files that need to be destroyed @@ -330,25 +332,34 @@ func (m *HyperVMachine) Stop(name string, opts machine.StopOptions) error { return vm.Stop() } +func (m *HyperVMachine) jsonConfigPath() (string, error) { + configDir, err := machine.GetConfDir(machine.HyperVVirt) + if err != nil { + return "", err + } + return getVMConfigPath(configDir, m.Name), nil +} + func (m *HyperVMachine) loadFromFile() (*HyperVMachine, error) { if len(m.Name) < 1 { return nil, errors.New("encountered machine with no name") } + + jsonPath, err := m.jsonConfigPath() + if err != nil { + return nil, err + } + mm := HyperVMachine{} + + if err := loadMacMachineFromJSON(jsonPath, &mm); err != nil { + return nil, err + } vmm := hypervctl.NewVirtualMachineManager() vm, err := vmm.GetMachine(m.Name) if err != nil { return nil, err } - configDir, err := machine.GetConfDir(machine.HyperVVirt) - if err != nil { - return nil, err - } - jsonPath := getVMConfigPath(configDir, m.Name) - mm := HyperVMachine{} - if err := loadMacMachineFromJSON(jsonPath, &mm); err != nil { - return nil, err - } cfg, err := vm.GetConfig(mm.ImagePath.GetPath()) if err != nil { return nil, err @@ -378,6 +389,9 @@ func getVMConfigPath(configDir, vmName string) string { func loadMacMachineFromJSON(fqConfigPath string, macMachine *HyperVMachine) error { b, err := os.ReadFile(fqConfigPath) if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return fmt.Errorf("%q: %w", fqConfigPath, machine.ErrNoSuchVM) + } return err } return json.Unmarshal(b, macMachine) diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/error.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/error.go index fc4bc6dfde..7fe985d979 100644 --- a/vendor/github.com/containers/libhvee/pkg/hypervctl/error.go +++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/error.go @@ -68,7 +68,6 @@ const ( ErrShutdownInProgress = 32782 ) - type shutdownCompError struct { errorCode int message string @@ -114,4 +113,45 @@ func translateShutdownError(code int) error { } return &shutdownCompError{code, message} -} \ No newline at end of file +} + +// Modify resource errors +const ( + ErrModifyResourceNotSupported = 1 + ErrModifyResourceFailed = 2 + ErrModifyResourceTimeout = 3 + ErrModifyResourceInvalidParameter = 4 + ErrModifyResourceInvalidState = 5 + ErrModifyResourceIncompatParam = 6 +) + +type modifyResourceError struct { + errorCode int + message string +} + +func (m *modifyResourceError) Error() string { + return fmt.Sprintf("%s (%d)", m.message, m.errorCode) +} + +func translateModifyError(code int) error { + var message string + switch code { + case ErrModifyResourceNotSupported: + message = "virtual machine does not support modification operations" + case ErrModifyResourceFailed: + message = "resource modification failed" + case ErrModifyResourceTimeout: + message = "timeout modifying resource" + case ErrModifyResourceInvalidParameter: + message = "a modify resource operation was passed an invalid parameter" + case ErrModifyResourceInvalidState: + message = "the requested modification could not be applied due to an invalid state" + case ErrModifyResourceIncompatParam: + message = "an incompatible parameter was passed to a modify resource operation" + default: + message = "unknown error" + } + + return &modifyResourceError{code, message} +} diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/memory_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/memory_settings.go index bd76e43be8..960694eb70 100644 --- a/vendor/github.com/containers/libhvee/pkg/hypervctl/memory_settings.go +++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/memory_settings.go @@ -3,6 +3,8 @@ package hypervctl +import "fmt" + const MemoryResourceType = "Microsoft:Hyper-V:Memory" type MemorySettings struct { @@ -41,7 +43,11 @@ type MemorySettings struct { } func createMemorySettings(settings *MemorySettings) (string, error) { - return createResourceSettingGeneric(settings, MemoryResourceType) + str, err := createResourceSettingGeneric(settings, MemoryResourceType) + if err != nil { + err = fmt.Errorf("could not create memory settings: %w", err) + } + return str, err } func fetchDefaultMemorySettings() (*MemorySettings, error) { diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/processor_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/processor_settings.go index a7703df4b4..9c0d6d95e8 100644 --- a/vendor/github.com/containers/libhvee/pkg/hypervctl/processor_settings.go +++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/processor_settings.go @@ -3,6 +3,8 @@ package hypervctl +import "fmt" + const ProcessorResourceType = "Microsoft:Hyper-V:Processor" /* @@ -88,5 +90,9 @@ func fetchDefaultProcessorSettings() (*ProcessorSettings, error) { } func createProcessorSettings(settings *ProcessorSettings) (string, error) { - return createResourceSettingGeneric(settings, ProcessorResourceType) + str, err := createResourceSettingGeneric(settings, ProcessorResourceType) + if err != nil { + err = fmt.Errorf("could not create processor settings: %w", err) + } + return str, err } diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/summary.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/summary.go index e330434f8c..c8abcef1b0 100644 --- a/vendor/github.com/containers/libhvee/pkg/hypervctl/summary.go +++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/summary.go @@ -46,12 +46,11 @@ const ( SummaryRequestOtherEnabledState = 132 ) - type SummaryRequestSet []uint var ( - // SummaryRequestCommon includes a smaller subset of commonly used fields + // SummaryRequestCommon includes a smaller subset of commonly used fields SummaryRequestCommon = SummaryRequestSet{ SummaryRequestName, SummaryRequestElementName, @@ -72,7 +71,7 @@ var ( SummaryRequestSwapFilesInUse, } - // SummaryRequestNearAll includes everything but load history and thumbnails + // SummaryRequestNearAll includes everything but load history and thumbnails SummaryRequestNearAll = SummaryRequestSet{ SummaryRequestName, SummaryRequestElementName, diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings.go index 3119a6de37..527a8574c2 100644 --- a/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings.go +++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings.go @@ -174,7 +174,7 @@ func addResource(service *wmiext.Service, systemSettingPath string, resourceSett return "", fmt.Errorf("AddResourceSettings failed: %w", err) } - err = waitVMResult(res, service, job) + err = waitVMResult(res, service, job, "failed to add resource", nil) if len(resultingSettings) > 0 { return resultingSettings[0], err diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings_builder.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings_builder.go index 71b6a6330d..119ba9e6d4 100644 --- a/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings_builder.go +++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/system_settings_builder.go @@ -139,9 +139,9 @@ func (builder *SystemSettingsBuilder) Build() (*SystemSettings, error) { return nil, fmt.Errorf("failed to define system: %w", err) } - err = waitVMResult(res, service, job) + err = waitVMResult(res, service, job, "failed to define system", nil) if err != nil { - return nil, fmt.Errorf("failed to define system: %w", err) + return nil, err } newSettings, err := service.FindFirstRelatedInstance(resultingSystem, "Msvm_VirtualSystemSettingData") diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vm.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vm.go index 989f9f0aa0..5636d4058e 100644 --- a/vendor/github.com/containers/libhvee/pkg/hypervctl/vm.go +++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vm.go @@ -183,18 +183,27 @@ func (vm *VirtualMachine) kvpOperation(op string, key string, value string, ille return err } -func waitVMResult(res int32, service *wmiext.Service, job *wmiext.Instance) error { +func waitVMResult(res int32, service *wmiext.Service, job *wmiext.Instance, errorMsg string, translate func(int) error) error { var err error - if res == 4096 { + switch res { + case 0: + return nil + case 4096: err = wmiext.WaitJob(service, job) defer job.Close() + default: + if translate != nil { + return translate(int(res)) + } + + return fmt.Errorf("%s (result code %d)", errorMsg, res) } if err != nil { desc, _ := job.GetAsString("ErrorDescription") desc = strings.Replace(desc, "\n", " ", -1) - return fmt.Errorf("failed to define system: %w (%s)", err, desc) + return fmt.Errorf("%s: %w (%s)", errorMsg, err, desc) } return err @@ -270,7 +279,7 @@ func (vm *VirtualMachine) Start() error { Out("ReturnValue", &res).End(); err != nil { return err } - return waitVMResult(res, srv, job) + return waitVMResult(res, srv, job, "failed to start vm", nil) } func getService(_ *wmiext.Service) (*wmiext.Service, error) { @@ -328,7 +337,7 @@ func (vm *VirtualMachine) GetSummaryInformation(requestedFields SummaryRequestSe } defer service.Close() - instance, err := service.FindFirstRelatedInstance(vm.Path(), "Msvm_VirtualSystemSettingData") + instance, err := vm.fetchSystemSettingsInstance(service) if err != nil { return nil, err } @@ -418,6 +427,98 @@ func (vmm *VirtualMachineManager) NewVirtualMachine(name string, config *Hardwar return nil } +func (vm *VirtualMachine) fetchSystemSettingsInstance(service *wmiext.Service) (*wmiext.Instance, error) { + // When a settings snapshot is taken there are multiple associations, use only the realized/active version + return service.FindFirstRelatedInstanceThrough(vm.Path(), "Msvm_VirtualSystemSettingData", "Msvm_SettingsDefineState") +} + +func (vm *VirtualMachine) fetchExistingResourceSettings(service *wmiext.Service, resourceType string, resourceSettings interface{}) error { + const errFmt = "could not fetch resource settings (%s): %w" + // When a settings snapshot is taken there are multiple associations, use only the realized/active version + instance, err := vm.fetchSystemSettingsInstance(service) + if err != nil { + return fmt.Errorf(errFmt, resourceType, err) + } + defer instance.Close() + + path, err := instance.Path() + if err != nil { + return fmt.Errorf(errFmt, resourceType, err) + + } + + return service.FindFirstRelatedObject(path, resourceType, resourceSettings) +} + +// Update processor and/or mem +func (vm *VirtualMachine) UpdateProcessorMemSettings(updateProcessor func(*ProcessorSettings), updateMemory func(*MemorySettings)) error { + service, err := wmiext.NewLocalService(HyperVNamespace) + if err != nil { + return err + } + defer service.Close() + + proc := &ProcessorSettings{} + mem := &MemorySettings{} + + var settings []string + if updateProcessor != nil { + err = vm.fetchExistingResourceSettings(service, "Msvm_ProcessorSettingData", proc) + if err != nil { + return err + } + + updateProcessor(proc) + + processorStr, err := createProcessorSettings(proc) + if err != nil { + return err + } + settings = append(settings, processorStr) + } + + if updateMemory != nil { + err = vm.fetchExistingResourceSettings(service, "Msvm_MemorySettingData", mem) + if err != nil { + return err + } + + updateMemory(mem) + + memStr, err := createMemorySettings(mem) + if err != nil { + return err + } + + settings = append(settings, memStr) + } + + if len(settings) < 1 { + return nil + } + + vsms, err := service.GetSingletonInstance("Msvm_VirtualSystemManagementService") + if err != nil { + return err + } + defer vsms.Close() + + var job *wmiext.Instance + var res int32 + err = vsms.BeginInvoke("ModifyResourceSettings"). + In("ResourceSettings", settings). + Execute(). + Out("Job", &job). + Out("ReturnValue", &res). + End() + + if err != nil { + return fmt.Errorf("failed to modify resource settings: %w", err) + } + + return waitVMResult(res, service, job, "failed to modify resource settings", translateModifyError) +} + func (vm *VirtualMachine) remove() (int32, error) { var ( err error @@ -433,7 +534,7 @@ func (vm *VirtualMachine) remove() (int32, error) { return -1, err } - wmiInst, err := srv.FindFirstRelatedInstance(vm.Path(), "Msvm_VirtualSystemSettingData") + wmiInst, err := vm.fetchSystemSettingsInstance(srv) if err != nil { return -1, err } @@ -448,7 +549,7 @@ func (vm *VirtualMachine) remove() (int32, error) { if err != nil { return -1, err } - defer wmiInst.Close() + defer vsms.Close() var ( job *wmiext.Instance @@ -465,7 +566,7 @@ func (vm *VirtualMachine) remove() (int32, error) { } // do i have this correct? you can get an error without a result? - if err := waitVMResult(res, srv, job); err != nil { + if err := waitVMResult(res, srv, job, "failed to remove vm", nil); err != nil { return -1, err } return res, nil diff --git a/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go b/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go index dadfc2e836..a7cce22081 100644 --- a/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go +++ b/vendor/github.com/containers/libhvee/pkg/hypervctl/vmm.go @@ -138,7 +138,7 @@ func (*VirtualMachineManager) CreateVhdxFile(path string, maxSize uint64) error return fmt.Errorf("failed to create vhdx: %w", err) } - return waitVMResult(ret, service, job) + return waitVMResult(ret, service, job, "failed to create vhdx", nil) } // GetSummaryInformation returns the live VM summary information for all virtual machines. diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/conversion.go b/vendor/github.com/containers/libhvee/pkg/wmiext/conversion.go index 5b9b68ee52..9dc9690606 100644 --- a/vendor/github.com/containers/libhvee/pkg/wmiext/conversion.go +++ b/vendor/github.com/containers/libhvee/pkg/wmiext/conversion.go @@ -17,8 +17,8 @@ import ( ) var ( - unixEpoch = time.Unix(0,0) - zeroTime = time.Time{} + unixEpoch = time.Unix(0, 0) + zeroTime = time.Time{} ) // Automation variants do not follow the OLE rules, instead they use the following mapping: @@ -346,7 +346,7 @@ func convertTimeToDataTime(time *time.Time) ole.VARIANT { return ole.NewVariant(ole.VT_BSTR, int64(uintptr(unsafe.Pointer(ole.SysAllocStringLen(s))))) } -func convertDurationToDateTime(duration time.Duration) ole.VARIANT { +func convertDurationToDateTime(duration time.Duration) ole.VARIANT { const daySeconds = time.Second * 86400 if duration == 0 { @@ -367,7 +367,7 @@ func convertDurationToDateTime(duration time.Duration) ole.VARIANT { micros := duration / time.Microsecond - s:=fmt.Sprintf("%08d%02d%02d%02d.%06d:000", days, hours, mins, seconds, micros) + s := fmt.Sprintf("%08d%02d%02d%02d.%06d:000", days, hours, mins, seconds, micros) return ole.NewVariant(ole.VT_BSTR, int64(uintptr(unsafe.Pointer(ole.SysAllocStringLen(s))))) } @@ -426,7 +426,7 @@ func parseIntervalTime(interval string) (time.Time, error) { } days, err := parseUintChain(interval[0:8], nil) - hours, err := parseUintChain(interval[8:10], err) + hours, err := parseUintChain(interval[8:10], err) mins, err := parseUintChain(interval[10:12], err) secs, err := parseUintChain(interval[12:14], err) micros, err := parseUintChain(interval[15:21], err) @@ -440,7 +440,7 @@ func parseIntervalTime(interval string) (time.Time, error) { stamp += hours * 3600 stamp += mins * 60 - return time.Unix(int64(stamp), int64(micros * 1000)), nil + return time.Unix(int64(stamp), int64(micros*1000)), nil } func convertIntervalToDuration(variant *ole.VARIANT) (time.Duration, error) { @@ -465,7 +465,6 @@ func parseUintChain(str string, err error) (uint64, error) { return strconv.ParseUint(str, 10, 0) } - func abs(num int) int { if num < 0 { return -num diff --git a/vendor/github.com/containers/libhvee/pkg/wmiext/service.go b/vendor/github.com/containers/libhvee/pkg/wmiext/service.go index eec30323eb..60bd42d8e6 100644 --- a/vendor/github.com/containers/libhvee/pkg/wmiext/service.go +++ b/vendor/github.com/containers/libhvee/pkg/wmiext/service.go @@ -306,6 +306,20 @@ func (s *Service) FindFirstRelatedInstance(objPath string, className string) (*I return s.FindFirstInstance(wql) } +// FindFirstRelatedInstanceThrough finds and returns a related associator of the specified WMI object path of the +// expected className type, and only through the expected association type. +func (s *Service) FindFirstRelatedInstanceThrough(objPath string, resultClass string, assocClass string) (*Instance, error) { + wql := fmt.Sprintf("ASSOCIATORS OF {%s} WHERE AssocClass = %s ResultClass = %s ", objPath, assocClass, resultClass) + return s.FindFirstInstance(wql) +} + +// FindFirstRelatedObject finds and returns a related associator of the specified WMI object path of the +// expected className type, and populates the passed in struct with its fields +func (s *Service) FindFirstRelatedObject(objPath string, className string, target interface{}) error { + wql := fmt.Sprintf("ASSOCIATORS OF {%s} WHERE ResultClass = %s", objPath, className) + return s.FindFirstObject(wql, target) +} + // FindFirstObject finds and returns the first WMI Instance in the result set for a WSL query, and // populates the specified struct pointer passed in through the target parameter. func (s *Service) FindFirstObject(wql string, target interface{}) error { diff --git a/vendor/modules.txt b/vendor/modules.txt index 01a08063c9..75aae2673f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -249,7 +249,7 @@ github.com/containers/image/v5/transports github.com/containers/image/v5/transports/alltransports github.com/containers/image/v5/types github.com/containers/image/v5/version -# github.com/containers/libhvee v0.0.1 +# github.com/containers/libhvee v0.0.2 ## explicit; go 1.18 github.com/containers/libhvee/pkg/hypervctl github.com/containers/libhvee/pkg/kvp/ginsu