Handle TypedParamStrings (#46)
* Handle TypedParamStrings Add handling for TypedParamStrings, which are different from the other TypedParam... types in that the decoded value is variable-sized.
This commit is contained in:
parent
c8e4b6a7b8
commit
a339d0ac95
184
libvirt.go
184
libvirt.go
@ -19,7 +19,6 @@ package libvirt
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -113,65 +112,129 @@ const (
|
|||||||
// FlagDomainAffectConfig means affect the persistent domain state.
|
// FlagDomainAffectConfig means affect the persistent domain state.
|
||||||
FlagDomainAffectConfig
|
FlagDomainAffectConfig
|
||||||
// FlagTypedParamStringOkay tells the server that this client understands
|
// FlagTypedParamStringOkay tells the server that this client understands
|
||||||
// TypedParameStrings.
|
// TypedParamStrings.
|
||||||
FlagTypedParamStringOkay
|
FlagTypedParamStringOkay
|
||||||
)
|
)
|
||||||
|
|
||||||
// Consts relating to TypedParams:
|
// Consts relating to TypedParams:
|
||||||
const (
|
const (
|
||||||
// TypedParamInt is a C int.
|
// TypeParamInt is a C int.
|
||||||
TypedParamInt = iota + 1
|
TypeParamInt = iota + 1
|
||||||
// TypedParamUInt is a C unsigned int.
|
// TypeParamUInt is a C unsigned int.
|
||||||
TypedParamUInt
|
TypeParamUInt
|
||||||
// TypedParamLLong is a C long long int.
|
// TypeParamLLong is a C long long int.
|
||||||
TypedParamLLong
|
TypeParamLLong
|
||||||
// TypedParamULLong is a C unsigned long long int.
|
// TypeParamULLong is a C unsigned long long int.
|
||||||
TypedParamULLong
|
TypeParamULLong
|
||||||
// TypedParamDouble is a C double.
|
// TypeParamDouble is a C double.
|
||||||
TypedParamDouble
|
TypeParamDouble
|
||||||
// TypedParamBoolean is a C char.
|
// TypeParamBoolean is a C char.
|
||||||
TypedParamBoolean
|
TypeParamBoolean
|
||||||
// TypedParamString is a C char*.
|
// TypeParamString is a C char*.
|
||||||
TypedParamString
|
TypeParamString
|
||||||
|
|
||||||
// TypedParamLast is just an end-of-enum marker.
|
// TypeParamLast is just an end-of-enum marker.
|
||||||
TypedParamLast
|
TypeParamLast
|
||||||
)
|
)
|
||||||
|
|
||||||
// TypedParam represents libvirt's virTypedParameter, which is used to pass
|
// TypedParam represents libvirt's virTypedParameter, which is used to pass
|
||||||
// typed parameters to libvirt functions. The `Value` field defined as a union
|
// typed parameters to libvirt functions. This is defined as an interface, and
|
||||||
// in libvirt, and given the current set of types inside it, is 8 bytes long.
|
// implemented by TypedParam... concrete types.
|
||||||
type TypedParam struct {
|
type TypedParam interface {
|
||||||
Field string
|
Field() string
|
||||||
Type int
|
Value() interface{}
|
||||||
Value [8]byte
|
}
|
||||||
|
|
||||||
|
// TypedParamInt contains a 32-bit signed integer.
|
||||||
|
type TypedParamInt struct {
|
||||||
|
Fld string
|
||||||
|
PType int32
|
||||||
|
Padding [4]byte
|
||||||
|
Val int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field returns the field name, a string name for the parameter.
|
||||||
|
func (tp *TypedParamInt) Field() string {
|
||||||
|
return tp.Fld
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the value for the typed parameter, as an empty interface.
|
||||||
|
func (tp *TypedParamInt) Value() interface{} {
|
||||||
|
return tp.Val
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTypedParamInt returns a TypedParam encoding for an int.
|
// NewTypedParamInt returns a TypedParam encoding for an int.
|
||||||
func NewTypedParamInt(name string, v int) *TypedParam {
|
func NewTypedParamInt(name string, v int32) *TypedParamInt {
|
||||||
// Truncate the field name if it's longer than the limit.
|
// Truncate the field name if it's longer than the limit.
|
||||||
if len(name) > constants.TypedParamFieldLength {
|
if len(name) > constants.TypedParamFieldLength {
|
||||||
name = name[:constants.TypedParamFieldLength]
|
name = name[:constants.TypedParamFieldLength]
|
||||||
}
|
}
|
||||||
tp := TypedParam{
|
tp := TypedParamInt{
|
||||||
Field: name,
|
Fld: name,
|
||||||
Type: TypedParamInt,
|
PType: TypeParamInt,
|
||||||
|
Val: v,
|
||||||
}
|
}
|
||||||
binary.BigEndian.PutUint32(tp.Value[:], uint32(v))
|
|
||||||
return &tp
|
return &tp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TypedParamULongLong contains a 64-bit unsigned integer.
|
||||||
|
type TypedParamULongLong struct {
|
||||||
|
Fld string
|
||||||
|
PType int32
|
||||||
|
Val uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field returns the field name, a string name for the parameter.
|
||||||
|
func (tp *TypedParamULongLong) Field() string {
|
||||||
|
return tp.Fld
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the value for the typed parameter, as an empty interface.
|
||||||
|
func (tp *TypedParamULongLong) Value() interface{} {
|
||||||
|
return tp.Val
|
||||||
|
}
|
||||||
|
|
||||||
// NewTypedParamULongLong returns a TypedParam encoding for an unsigned long long.
|
// NewTypedParamULongLong returns a TypedParam encoding for an unsigned long long.
|
||||||
func NewTypedParamULongLong(name string, v uint64) *TypedParam {
|
func NewTypedParamULongLong(name string, v uint64) *TypedParamULongLong {
|
||||||
// Truncate the field name if it's longer than the limit.
|
// Truncate the field name if it's longer than the limit.
|
||||||
if len(name) > constants.TypedParamFieldLength {
|
if len(name) > constants.TypedParamFieldLength {
|
||||||
name = name[:constants.TypedParamFieldLength]
|
name = name[:constants.TypedParamFieldLength]
|
||||||
}
|
}
|
||||||
tp := TypedParam{
|
tp := TypedParamULongLong{
|
||||||
Field: name,
|
Fld: name,
|
||||||
Type: TypedParamULLong,
|
PType: TypeParamULLong,
|
||||||
|
Val: v,
|
||||||
|
}
|
||||||
|
return &tp
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypedParamString contains a string parameter.
|
||||||
|
type TypedParamString struct {
|
||||||
|
Fld string
|
||||||
|
PType int
|
||||||
|
Val string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field returns the field name, a string name for the parameter.
|
||||||
|
func (tp *TypedParamString) Field() string {
|
||||||
|
return tp.Fld
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the value for the typed parameter, as an empty interface.
|
||||||
|
func (tp *TypedParamString) Value() interface{} {
|
||||||
|
return tp.Val
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTypedParamString returns a typed parameter containing the passed string.
|
||||||
|
func NewTypedParamString(name string, v string) TypedParam {
|
||||||
|
if len(name) > constants.TypedParamFieldLength {
|
||||||
|
name = name[:constants.TypedParamFieldLength]
|
||||||
|
}
|
||||||
|
tp := TypedParamString{
|
||||||
|
Fld: name,
|
||||||
|
PType: TypeParamString,
|
||||||
|
Val: v,
|
||||||
}
|
}
|
||||||
binary.BigEndian.PutUint64(tp.Value[:], v)
|
|
||||||
return &tp
|
return &tp
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1295,6 +1358,7 @@ type BlockLimit struct {
|
|||||||
// not necessarily the only possible values; different libvirt versions may add
|
// not necessarily the only possible values; different libvirt versions may add
|
||||||
// or remove parameters from this list.
|
// or remove parameters from this list.
|
||||||
const (
|
const (
|
||||||
|
QEMUBlockIOGroupName = "group_name"
|
||||||
QEMUBlockIOTotalBytesSec = "total_bytes_sec"
|
QEMUBlockIOTotalBytesSec = "total_bytes_sec"
|
||||||
QEMUBlockIOReadBytesSec = "read_bytes_sec"
|
QEMUBlockIOReadBytesSec = "read_bytes_sec"
|
||||||
QEMUBlockIOWriteBytesSec = "write_bytes_sec"
|
QEMUBlockIOWriteBytesSec = "write_bytes_sec"
|
||||||
@ -1347,14 +1411,13 @@ func (l *Libvirt) SetBlockIOTune(dom string, disk string, limits ...BlockLimit)
|
|||||||
|
|
||||||
for _, limit := range limits {
|
for _, limit := range limits {
|
||||||
tp := NewTypedParamULongLong(limit.Name, limit.Value)
|
tp := NewTypedParamULongLong(limit.Name, limit.Value)
|
||||||
payload.Params = append(payload.Params, *tp)
|
payload.Params = append(payload.Params, tp)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf, err := encode(&payload)
|
buf, err := encode(&payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := l.request(constants.ProcDomainSetBlockIOTune, constants.ProgramRemote, &buf)
|
resp, err := l.request(constants.ProcDomainSetBlockIOTune, constants.ProgramRemote, &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1403,20 +1466,49 @@ func (l *Libvirt) GetBlockIOTune(dom string, disk string) ([]BlockLimit, error)
|
|||||||
return nil, decodeError(r.Payload)
|
return nil, decodeError(r.Payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
dec := xdr.NewDecoder(bytes.NewReader(r.Payload))
|
var limits []BlockLimit
|
||||||
result := struct {
|
rdr := bytes.NewReader(r.Payload)
|
||||||
Limits []TypedParam
|
dec := xdr.NewDecoder(rdr)
|
||||||
ParamCount uint32
|
|
||||||
}{}
|
// find out how many params were returned
|
||||||
_, err = dec.Decode(&result)
|
paramCount, _, err := dec.DecodeInt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
limits := make([]BlockLimit, len(result.Limits))
|
// now decode each of the returned TypedParams. To do this we read the field
|
||||||
for ix := range result.Limits {
|
// name and type, then use the type information to decode the value.
|
||||||
limits[ix].Name = result.Limits[ix].Field
|
for param := int32(0); param < paramCount; param++ {
|
||||||
limits[ix].Value = binary.BigEndian.Uint64(result.Limits[ix].Value[:])
|
// Get the field name
|
||||||
|
name, _, err := dec.DecodeString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// ...and the type
|
||||||
|
ptype, _, err := dec.DecodeInt()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can read the actual value.
|
||||||
|
switch ptype {
|
||||||
|
case TypeParamULLong:
|
||||||
|
var val uint64
|
||||||
|
_, err = dec.Decode(&val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lim := BlockLimit{name, val}
|
||||||
|
limits = append(limits, lim)
|
||||||
|
case TypeParamString:
|
||||||
|
var val string
|
||||||
|
_, err = dec.Decode(&val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// This routine doesn't currently return strings. As of libvirt 3+,
|
||||||
|
// there's one string here, `group_name`.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return limits, nil
|
return limits, nil
|
||||||
|
@ -414,7 +414,7 @@ var testSetBlockIoTuneReply = []byte{
|
|||||||
// the result returned by an actual call to GetBlockIoTune, and then adding the
|
// the result returned by an actual call to GetBlockIoTune, and then adding the
|
||||||
// standard header to the beginning. The length parameter has to be correct!
|
// standard header to the beginning. The length parameter has to be correct!
|
||||||
var testGetBlockIoTuneReply = []byte{
|
var testGetBlockIoTuneReply = []byte{
|
||||||
0x00, 0x00, 0x02, 0xe0, // length
|
0x00, 0x00, 0x03, 0x00, // length
|
||||||
0x20, 0x00, 0x80, 0x86, // program
|
0x20, 0x00, 0x80, 0x86, // program
|
||||||
0x00, 0x00, 0x00, 0x01, // version
|
0x00, 0x00, 0x00, 0x01, // version
|
||||||
0x00, 0x00, 0x00, 0xfd, // procedure
|
0x00, 0x00, 0x00, 0xfd, // procedure
|
||||||
@ -422,7 +422,7 @@ var testGetBlockIoTuneReply = []byte{
|
|||||||
0x00, 0x00, 0x00, 0x00, // serial
|
0x00, 0x00, 0x00, 0x00, // serial
|
||||||
0x00, 0x00, 0x00, 0x00, // status
|
0x00, 0x00, 0x00, 0x00, // status
|
||||||
|
|
||||||
0x0, 0x0, 0x0, 0x13, // 13 TypedParams follow
|
0x0, 0x0, 0x0, 0x14, // 14 TypedParams follow
|
||||||
|
|
||||||
0x0, 0x0, 0x0, 0xf, // field name is 15 bytes, padded to a multiple of 4
|
0x0, 0x0, 0x0, 0xf, // field name is 15 bytes, padded to a multiple of 4
|
||||||
0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x0,
|
0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x0,
|
||||||
@ -519,6 +519,12 @@ var testGetBlockIoTuneReply = []byte{
|
|||||||
0x0, 0x0, 0x0, 0x4,
|
0x0, 0x0, 0x0, 0x4,
|
||||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
|
||||||
|
0x0, 0x0, 0x0, 0xa, // This is field "group_name", a string (type 7), whose value is "somename"
|
||||||
|
0x67, 0x72, 0x6F, 0x75, 0x70, 0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x7,
|
||||||
|
0x0, 0x0, 0x0, 0x8,
|
||||||
|
0x73, 0x6F, 0x6D, 0x65, 0x6E, 0x61, 0x6D, 0x65,
|
||||||
|
|
||||||
0x0, 0x0, 0x0, 0x0, // End of TypedParams
|
0x0, 0x0, 0x0, 0x0, // End of TypedParams
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user