139 lines
3.0 KiB
Go
139 lines
3.0 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package hypervctl
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
"github.com/containers/libhvee/pkg/wmiext"
|
|
)
|
|
|
|
const (
|
|
KvpOperationFailed = 32768
|
|
KvpAccessDenied = 32769
|
|
KvpNotSupported = 32770
|
|
KvpStatusUnknown = 32771
|
|
KvpTimeoutOccurred = 32772
|
|
KvpIllegalArgument = 32773
|
|
KvpSystemInUse = 32774
|
|
KvpInvalidState = 32775
|
|
KvpIncorrectDataType = 32776
|
|
KvpSystemNotAvailable = 32777
|
|
KvpOutOfMemory = 32778
|
|
KvpNotFound = 32779
|
|
|
|
KvpExchangeDataItemName = "Msvm_KvpExchangeDataItem"
|
|
MemorySettingDataName = "Msvm_MemorySettingData"
|
|
)
|
|
|
|
type CimKvpItems struct {
|
|
Instances []CimKvpItem `xml:"INSTANCE"`
|
|
}
|
|
|
|
type CimKvpItem struct {
|
|
Properties []CimKvpItemProperty `xml:"PROPERTY"`
|
|
}
|
|
|
|
type CimKvpItemProperty struct {
|
|
Name string `xml:"NAME,attr"`
|
|
Value string `xml:"VALUE"`
|
|
}
|
|
|
|
type KvpError struct {
|
|
ErrorCode int
|
|
message string
|
|
}
|
|
|
|
func (k *KvpError) Error() string {
|
|
return fmt.Sprintf("%s (%d)", k.message, k.ErrorCode)
|
|
}
|
|
|
|
func createKvpItem(service *wmiext.Service, key string, value string) (string, error) {
|
|
item, err := service.SpawnInstance(KvpExchangeDataItemName)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer item.Close()
|
|
|
|
_ = item.Put("Name", key)
|
|
_ = item.Put("Data", value)
|
|
_ = item.Put("Source", 0)
|
|
itemStr := item.GetCimText()
|
|
return itemStr, nil
|
|
}
|
|
|
|
func parseKvpMapXml(kvpXml string) (map[string]string, error) {
|
|
// Workaround XML decoder's inability to handle multiple root elements
|
|
r := io.MultiReader(
|
|
strings.NewReader("<root>"),
|
|
strings.NewReader(kvpXml),
|
|
strings.NewReader("</root>"),
|
|
)
|
|
|
|
var items CimKvpItems
|
|
if err := xml.NewDecoder(r).Decode(&items); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret := make(map[string]string)
|
|
for _, item := range items.Instances {
|
|
var key, value string
|
|
for _, prop := range item.Properties {
|
|
if strings.EqualFold(prop.Name, "Name") {
|
|
key = prop.Value
|
|
} else if strings.EqualFold(prop.Name, "Data") {
|
|
value = prop.Value
|
|
}
|
|
}
|
|
if len(key) > 0 {
|
|
ret[key] = value
|
|
}
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func translateKvpError(source error, illegalSuggestion string) error {
|
|
j, ok := source.(*wmiext.JobError)
|
|
|
|
if !ok {
|
|
return source
|
|
}
|
|
|
|
var message string
|
|
switch j.ErrorCode {
|
|
case KvpOperationFailed:
|
|
message = "Operation failed"
|
|
case KvpAccessDenied:
|
|
message = "Access denied"
|
|
case KvpNotSupported:
|
|
message = "Not supported"
|
|
case KvpStatusUnknown:
|
|
message = "Status is unknown"
|
|
case KvpTimeoutOccurred:
|
|
message = "Timeout occurred"
|
|
case KvpIllegalArgument:
|
|
message = "Illegal argument (" + illegalSuggestion + ")"
|
|
case KvpSystemInUse:
|
|
message = "System is in use"
|
|
case KvpInvalidState:
|
|
message = "Invalid state for this operation"
|
|
case KvpIncorrectDataType:
|
|
message = "Incorrect data type"
|
|
case KvpSystemNotAvailable:
|
|
message = "System is not available"
|
|
case KvpOutOfMemory:
|
|
message = "Out of memory"
|
|
case KvpNotFound:
|
|
message = "Not found"
|
|
default:
|
|
return source
|
|
}
|
|
|
|
return &KvpError{j.ErrorCode, message}
|
|
}
|