Generate libvirt procedure wrappers.

The generated wrappers have an argument for every field in their "Args"
struct, and return everything in their "Ret" struct (these structs are
defined in the protocol file, and identified by procedure name).
Marshaling and unmarshaling is handled inside the generated procedures.
This commit is contained in:
Geoff Hickey 2017-11-13 15:18:18 -05:00
parent fb16117ff9
commit deb7a54ff8
9 changed files with 16134 additions and 2700 deletions

View File

@ -16,3 +16,4 @@ Michael Koppmann <me@mkoppmann.at>
Simarpreet Singh <simar@linux.com> Simarpreet Singh <simar@linux.com>
Alexander Polyakov <apolyakov@beget.com> Alexander Polyakov <apolyakov@beget.com>
Amanda Andrade <amanda.andrade@serpro.gov.br> Amanda Andrade <amanda.andrade@serpro.gov.br>
Geoff Hickey <ghickey@digitalocean.com>

View File

@ -71,10 +71,14 @@ type Generator struct {
Consts []ConstItem Consts []ConstItem
// Structs holds a list of all the structs found by the parser // Structs holds a list of all the structs found by the parser
Structs []Structure Structs []Structure
// Typedefs hold all the type definitions from 'typedef ...' lines. // StructMap is a map of the structs we find for quick searching.
StructMap map[string]int
// Typedefs holds all the type definitions from 'typedef ...' lines.
Typedefs []Typedef Typedefs []Typedef
// Unions hold all the discriminated unions // Unions holds all the discriminated unions.
Unions []Union Unions []Union
// Procs holds all the discovered libvirt procedures.
Procs []Proc
} }
// Gen accumulates items as the parser runs, and is then used to produce the // Gen accumulates items as the parser runs, and is then used to produce the
@ -85,15 +89,48 @@ var Gen Generator
// explicitly given a value. // explicitly given a value.
var CurrentEnumVal int64 var CurrentEnumVal int64
// oneRuneTokens lists the runes the lexer will consider to be tokens when it // goEquivTypes maps the basic types defined in the rpc spec to their golang
// finds them. These are returned to the parser using the integer value of their // equivalents.
// runes. var goEquivTypes = map[string]string{
var oneRuneTokens = `{}[]<>(),=;:*` // Some of the identifiers in the rpc specification are reserved words or
// pre-existing types in go. This renames them to something safe.
var reservedIdentifiers = map[string]string{
"type": "lvtype", "type": "lvtype",
"string": "lvstring",
"error": "lverror", "error": "lverror",
"nil": "lvnil",
// The libvirt spec uses this NonnullString type, which is a string with a
// specified maximum length. This makes the go code more confusing, and
// we're not enforcing the limit anyway, so collapse it here. This also
// requires us to ditch the typedef that would otherwise be generated.
"NonnullString": "string",
"String": "string",
"Int": "int",
"Uint": "uint",
"Int8": "int8",
"Uint8": "uint8",
"Int16": "int16",
"Uint16": "uint16",
"Int32": "int32",
"Uint32": "uint32",
"Int64": "int64",
"Uint64": "uint64",
"Float32": "float32",
"Float64": "float64",
"Bool": "bool",
"Byte": "byte",
}
// These defines are from libvirt-common.h. They should be fetched from there,
// but for now they're hardcoded here.
var lvTypedParams = map[string]uint32{
"VIR_TYPED_PARAM_INT": 1,
"VIR_TYPED_PARAM_UINT": 2,
"VIR_TYPED_PARAM_LLONG": 3,
"VIR_TYPED_PARAM_ULLONG": 4,
"VIR_TYPED_PARAM_DOUBLE": 5,
"VIR_TYPED_PARAM_BOOLEAN": 6,
"VIR_TYPED_PARAM_STRING": 7,
} }
// Decl records a declaration, like 'int x' or 'remote_nonnull_string str' // Decl records a declaration, like 'int x' or 'remote_nonnull_string str'
@ -123,14 +160,50 @@ type Union struct {
// Case holds a single case of a discriminated union. // Case holds a single case of a discriminated union.
type Case struct { type Case struct {
CaseName string
DiscriminantVal string DiscriminantVal string
Type Decl Decl
} }
// Proc holds information about a libvirt procedure the parser has found.
type Proc struct {
Num int64
Name string
Args []Decl
Ret []Decl
ArgsStruct string
RetStruct string
}
type structStack []*Structure
// CurrentStruct will point to a struct record if we're in a struct declaration. // CurrentStruct will point to a struct record if we're in a struct declaration.
// When the parser adds a declaration, it will be added to the open struct if // When the parser adds a declaration, it will be added to the open struct if
// there is one. // there is one.
var CurrentStruct *Structure var CurrentStruct structStack
// Since it's possible to have an embedded struct definition, this implements
// a stack to keep track of the current structure.
func (s *structStack) empty() bool {
return len(*s) == 0
}
func (s *structStack) push(st *Structure) {
*s = append(*s, st)
}
func (s *structStack) pop() *Structure {
if s.empty() {
return nil
}
st := (*s)[len(*s)-1]
*s = (*s)[:len(*s)-1]
return st
}
func (s *structStack) peek() *Structure {
if s.empty() {
return nil
}
return (*s)[len(*s)-1]
}
// CurrentTypedef will point to a typedef record if we're parsing one. Typedefs // CurrentTypedef will point to a typedef record if we're parsing one. Typedefs
// can define a struct or union type, but the preferred for is struct xxx{...}, // can define a struct or union type, but the preferred for is struct xxx{...},
@ -148,6 +221,7 @@ var CurrentCase *Case
// the path to the root of the libvirt source directory to use for the // the path to the root of the libvirt source directory to use for the
// generation. // generation.
func Generate(proto io.Reader) error { func Generate(proto io.Reader) error {
Gen.StructMap = make(map[string]int)
lexer, err := NewLexer(proto) lexer, err := NewLexer(proto)
if err != nil { if err != nil {
return err return err
@ -162,6 +236,10 @@ func Generate(proto io.Reader) error {
return fmt.Errorf("failed to parse libvirt protocol: %v", rv) return fmt.Errorf("failed to parse libvirt protocol: %v", rv)
} }
// When parsing is done, we can link the procedures we've found to their
// argument types.
procLink()
// Generate and write the output. // Generate and write the output.
constFile, err := os.Create("../constants/constants.gen.go") constFile, err := os.Create("../constants/constants.gen.go")
if err != nil { if err != nil {
@ -216,26 +294,44 @@ func genGo(constFile, procFile io.Writer) error {
// also tries to upcase abbreviations so a name like DOMAIN_GET_XML becomes // also tries to upcase abbreviations so a name like DOMAIN_GET_XML becomes
// DomainGetXML, not DomainGetXml. // DomainGetXML, not DomainGetXml.
func constNameTransform(name string) string { func constNameTransform(name string) string {
nn := fromSnakeToCamel(strings.TrimPrefix(name, "REMOTE_"), true) decamelize := strings.ContainsRune(name, '_')
nn := strings.TrimPrefix(name, "REMOTE_")
if decamelize {
nn = fromSnakeToCamel(nn, true)
}
nn = fixAbbrevs(nn) nn = fixAbbrevs(nn)
return nn return nn
} }
func identifierTransform(name string) string { func identifierTransform(name string) string {
decamelize := strings.ContainsRune(name, '_')
nn := strings.TrimPrefix(name, "remote_") nn := strings.TrimPrefix(name, "remote_")
nn = fromSnakeToCamel(nn, false) if decamelize {
nn = fromSnakeToCamel(nn, true)
} else {
nn = publicize(nn)
}
nn = fixAbbrevs(nn) nn = fixAbbrevs(nn)
nn = checkIdentifier(nn) nn = checkIdentifier(nn)
return nn return nn
} }
func typeTransform(name string) string { func typeTransform(name string) string {
nn := strings.TrimLeft(name, "*") nn := strings.TrimLeft(name, "*[]")
diff := len(name) - len(nn) diff := len(name) - len(nn)
nn = identifierTransform(nn) nn = identifierTransform(nn)
return name[0:diff] + nn return name[0:diff] + nn
} }
func publicize(name string) string {
if len(name) <= 0 {
return name
}
r, n := utf8.DecodeRuneInString(name)
name = string(unicode.ToUpper(r)) + name[n:]
return name
}
// fromSnakeToCamel transmutes a snake-cased string to a camel-cased one. All // fromSnakeToCamel transmutes a snake-cased string to a camel-cased one. All
// runes that follow an underscore are up-cased, and the underscores themselves // runes that follow an underscore are up-cased, and the underscores themselves
// are omitted. // are omitted.
@ -292,6 +388,30 @@ func fixAbbrevs(s string) string {
return s return s
} }
// procLink associates a libvirt procedure with the types that are its arguments
// and return values, filling out those fields in the procedure struct. These
// types are extracted by iterating through the argument and return structures
// defined in the protocol file. If one or both of these structs is not defined
// then either the args or return values are empty.
func procLink() {
for ix, proc := range Gen.Procs {
argsName := proc.Name + "Args"
retName := proc.Name + "Ret"
argsIx, hasArgs := Gen.StructMap[argsName]
retIx, hasRet := Gen.StructMap[retName]
if hasArgs {
argsStruct := Gen.Structs[argsIx]
Gen.Procs[ix].ArgsStruct = argsStruct.Name
Gen.Procs[ix].Args = argsStruct.Members
}
if hasRet {
retStruct := Gen.Structs[retIx]
Gen.Procs[ix].RetStruct = retStruct.Name
Gen.Procs[ix].Ret = retStruct.Members
}
}
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Routines called by the parser's actions. // Routines called by the parser's actions.
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -327,6 +447,7 @@ func addEnumVal(name string, val int64) error {
name = constNameTransform(name) name = constNameTransform(name)
Gen.EnumVals = append(Gen.EnumVals, ConstItem{name, fmt.Sprintf("%d", val)}) Gen.EnumVals = append(Gen.EnumVals, ConstItem{name, fmt.Sprintf("%d", val)})
CurrentEnumVal = val CurrentEnumVal = val
addProc(name, val)
return nil return nil
} }
@ -341,6 +462,17 @@ func AddConst(name, val string) error {
return nil return nil
} }
// addProc checks an enum value to see if it's a procedure number. If so, we
// add the procedure to our list for later generation.
func addProc(name string, val int64) {
if !strings.HasPrefix(name, "Proc") {
return
}
name = name[4:]
proc := &Proc{Num: val, Name: name}
Gen.Procs = append(Gen.Procs, *proc)
}
// parseNumber makes sure that a parsed numerical value can be parsed to a 64- // parseNumber makes sure that a parsed numerical value can be parsed to a 64-
// bit integer. // bit integer.
func parseNumber(val string) (int64, error) { func parseNumber(val string) (int64, error) {
@ -357,25 +489,22 @@ func parseNumber(val string) (int64, error) {
// before the member declarations are processed. // before the member declarations are processed.
func StartStruct(name string) { func StartStruct(name string) {
name = identifierTransform(name) name = identifierTransform(name)
CurrentStruct = &Structure{Name: name} CurrentStruct.push(&Structure{Name: name})
} }
// AddStruct is called when the parser has finished parsing a struct. It adds // AddStruct is called when the parser has finished parsing a struct. It adds
// the now-complete struct definition to the generator's list. // the now-complete struct definition to the generator's list.
func AddStruct() { func AddStruct() {
Gen.Structs = append(Gen.Structs, *CurrentStruct) st := *CurrentStruct.pop()
CurrentStruct = nil Gen.Structs = append(Gen.Structs, st)
Gen.StructMap[st.Name] = len(Gen.Structs) - 1
} }
// StartTypedef is called when the parser finds a typedef.
func StartTypedef() { func StartTypedef() {
CurrentTypedef = &Typedef{} CurrentTypedef = &Typedef{}
} }
// TODO: remove before flight
func Beacon(name string) {
fmt.Println(name)
}
// StartUnion is called by the parser when it finds a union declaraion. // StartUnion is called by the parser when it finds a union declaraion.
func StartUnion(name string) { func StartUnion(name string) {
name = identifierTransform(name) name = identifierTransform(name)
@ -384,16 +513,34 @@ func StartUnion(name string) {
// AddUnion is called by the parser when it has finished processing a union // AddUnion is called by the parser when it has finished processing a union
// type. It adds the union to the generator's list and clears the CurrentUnion // type. It adds the union to the generator's list and clears the CurrentUnion
// pointer. // pointer. We handle unions by declaring an interface for the union type, and
// adding methods to each of the cases so that they satisfy the interface.
func AddUnion() { func AddUnion() {
Gen.Unions = append(Gen.Unions, *CurrentUnion) Gen.Unions = append(Gen.Unions, *CurrentUnion)
CurrentUnion = nil CurrentUnion = nil
} }
// StartCase is called when the parser finds a case statement within a union.
func StartCase(dvalue string) { func StartCase(dvalue string) {
CurrentCase = &Case{DiscriminantVal: dvalue} // In libvirt, the discriminant values are all C pre- processor definitions.
// Since we don't run the C pre-processor on the protocol file, they're
// still just names when we get them - we don't actually have their integer
// values. We'll use the strings to build the type names, although this is
// brittle, because we're defining a type for each of the case values, and
// that type needs a name.
caseName := dvalue
if ix := strings.LastIndexByte(caseName, '_'); ix != -1 {
caseName = caseName[ix+1:]
}
caseName = fromSnakeToCamel(caseName, true)
dv, ok := lvTypedParams[dvalue]
if ok {
dvalue = strconv.FormatUint(uint64(dv), 10)
}
CurrentCase = &Case{CaseName: caseName, DiscriminantVal: dvalue}
} }
// AddCase is called when the parser finishes parsing a case.
func AddCase() { func AddCase() {
CurrentUnion.Cases = append(CurrentUnion.Cases, *CurrentCase) CurrentUnion.Cases = append(CurrentUnion.Cases, *CurrentCase)
CurrentCase = nil CurrentCase = nil
@ -403,27 +550,59 @@ func AddCase() {
// The declaration will be added to any open container (such as a struct, if the // The declaration will be added to any open container (such as a struct, if the
// parser is working through a struct definition.) // parser is working through a struct definition.)
func AddDeclaration(identifier, itype string) { func AddDeclaration(identifier, itype string) {
// TODO: panic if not in a struct/union/typedef? // fmt.Println("adding", identifier, itype)
// If the name is a reserved word, transform it so it isn't. // If the name is a reserved word, transform it so it isn't.
identifier = identifierTransform(identifier) identifier = identifierTransform(identifier)
itype = typeTransform(itype) itype = typeTransform(itype)
decl := &Decl{Name: identifier, Type: itype} decl := Decl{Name: identifier, Type: itype}
if CurrentStruct != nil { if !CurrentStruct.empty() {
CurrentStruct.Members = append(CurrentStruct.Members, *decl) st := CurrentStruct.peek()
st.Members = append(st.Members, decl)
} else if CurrentTypedef != nil { } else if CurrentTypedef != nil {
CurrentTypedef.Name = identifier CurrentTypedef.Name = identifier
CurrentTypedef.Type = itype CurrentTypedef.Type = itype
if identifier != "string" {
// Omit recursive typedefs. These happen because we're massaging
// some of the type names.
Gen.Typedefs = append(Gen.Typedefs, *CurrentTypedef) Gen.Typedefs = append(Gen.Typedefs, *CurrentTypedef)
}
CurrentTypedef = nil CurrentTypedef = nil
} else if CurrentCase != nil { } else if CurrentCase != nil {
CurrentCase.Type = *decl CurrentCase.Name = identifier
CurrentCase.Type = itype
} else if CurrentUnion != nil { } else if CurrentUnion != nil {
CurrentUnion.DiscriminantType = itype CurrentUnion.DiscriminantType = itype
} }
} }
// AddFixedArray is called by the parser to add a fixed-length array to the
// current container (struct, union, etc). Fixed-length arrays are not length-
// prefixed.
func AddFixedArray(identifier, itype, len string) {
atype := fmt.Sprintf("[%v]%v", len, itype)
AddDeclaration(identifier, atype)
}
// AddVariableArray is called by the parser to add a variable-length array.
// Variable-length arrays are prefixed with a 32-bit unsigned length, and may
// also have a maximum length specified.
func AddVariableArray(identifier, itype, len string) {
// FIXME: This ignores the length restriction, so as of now we can't check
// to make sure that we're not exceeding that restriction when we fill in
// message buffers. That may not matter, if libvirt's checking is careful
// enough. This could be handled with a map, however.
atype := fmt.Sprintf("[]%v", itype)
// Handle strings specially. In the rpcgen definition a string is specified
// as a variable-length array, either with or without a max length. We want
// these to be go strings, so we'll just remove the array specifier.
if itype == "string" {
atype = itype
}
AddDeclaration(identifier, atype)
}
func checkIdentifier(i string) string { func checkIdentifier(i string) string {
nn, reserved := reservedIdentifiers[i] nn, reserved := goEquivTypes[i]
if reserved { if reserved {
return nn return nn
} }

View File

@ -26,6 +26,11 @@ import (
// eof is returned by the lexer when there's no more input. // eof is returned by the lexer when there's no more input.
const eof = -1 const eof = -1
// oneRuneTokens lists the runes the lexer will consider to be tokens when it
// finds them. These are returned to the parser using the integer value of their
// runes.
var oneRuneTokens = `{}[]<>(),=;:*`
type item struct { type item struct {
typ int typ int
val string val string

View File

@ -6,6 +6,17 @@
package libvirt package libvirt
import (
"bytes"
"github.com/davecgh/go-xdr/xdr2"
"github.com/digitalocean/go-libvirt/internal/constants"
)
const (
VirUUIDBuflen = 16
)
// Typedefs: // Typedefs:
{{range .Typedefs}}type {{.Name}} {{.Type}} {{range .Typedefs}}type {{.Name}} {{.Type}}
{{end}} {{end}}
@ -17,9 +28,60 @@ package libvirt
{{range .Members}} {{.Name}} {{.Type}} {{range .Members}} {{.Name}} {{.Type}}
{{end -}} {{end -}}
} }
{{end}} {{end}}
// Unions: // Unions:
{{range .Unions}}type {{.Name}} struct { {{range .Unions}}type {{.Name}} interface {
discriminant {{.DiscriminantType}} Get() interface{}
{{end -}} {{end -}}
} }
{{range .Unions}}{{$uname := .Name}}{{range .Cases}}{{$casetype := printf "%v%v" $uname .CaseName}}
type {{$casetype}} struct {
DVal uint32
{{.Name}} {{.Type}}
}
func New{{$casetype}}(v {{.Type}}) *{{$casetype}} { return &{{$casetype}}{DVal: {{.DiscriminantVal}}, {{.Name}}: v} }
func (c *{{$casetype}}) Get() interface{} { return c.{{.Name}} }
{{end}}
{{- end}}
// Procedures:
{{range .Procs}}
func (l *Libvirt) {{.Name}}({{range $ix, $arg := .Args}}{{if $ix}}, {{end}}{{.Name}} {{.Type}}{{end}}) ({{range .Ret}}r{{.Name}} {{.Type}}, {{end}}err error) {
var buf bytes.Buffer
{{if .ArgsStruct}}
args := {{.ArgsStruct}} {
{{range .Args}} {{.Name}}: {{.Name}},
{{end}} }
buf, err = encode(&args)
if err != nil {
return
}
{{end}}
var resp <-chan response
resp, err = l.request({{.Num}}, constants.Program, &buf)
if err != nil {
return
}
r := <-resp
if r.Status != StatusOK {
err = decodeError(r.Payload)
return
}
{{if .RetStruct}}
result := {{.RetStruct}}{}
rdr := bytes.NewReader(r.Payload)
dec := xdr.NewDecoder(rdr)
_, err = dec.Decode(&result)
if err != nil {
return
}
{{range .Ret}} r{{.Name}} = result.{{.Name}}
{{end}}{{end}}
return
}
{{end}}

View File

@ -119,7 +119,7 @@ type_specifier
| DOUBLE {$$.val = "float64"} | DOUBLE {$$.val = "float64"}
| BOOL {$$.val = "bool"} | BOOL {$$.val = "bool"}
| STRING {$$.val = "string"} | STRING {$$.val = "string"}
| OPAQUE {$$.val = "[]byte"} | OPAQUE {$$.val = "byte"}
| enum_definition | enum_definition
| struct_definition | struct_definition
| union_definition | union_definition
@ -138,12 +138,12 @@ variable_ident
; ;
fixed_array_declaration fixed_array_declaration
: type_specifier variable_ident '[' value ']' { AddDeclaration($2.val, $1.val) } // FIXME: Handle the max size (value)? : type_specifier variable_ident '[' value ']' { AddFixedArray($2.val, $1.val, $4.val) }
; ;
variable_array_declaration variable_array_declaration
: type_specifier variable_ident '<' value '>' { AddDeclaration($2.val, $1.val) } // FIXME: Handle the max size (value)? : type_specifier variable_ident '<' value '>' { AddVariableArray($2.val, $1.val, $4.val) }
| type_specifier variable_ident '<' '>' { AddDeclaration($2.val, $1.val) } | type_specifier variable_ident '<' '>' { AddVariableArray($2.val, $1.val, "") }
; ;
pointer_declaration pointer_declaration

File diff suppressed because it is too large Load Diff

View File

@ -53,11 +53,11 @@ type Libvirt struct {
} }
// Domain represents a domain as seen by libvirt. // Domain represents a domain as seen by libvirt.
type Domain struct { // type Domain struct {
Name string // Name string
UUID [constants.UUIDSize]byte // UUID [constants.UUIDSize]byte
ID int // ID int
} // }
// DomainEvent represents a libvirt domain event. // DomainEvent represents a libvirt domain event.
type DomainEvent struct { type DomainEvent struct {
@ -71,17 +71,17 @@ type DomainEvent struct {
} }
// Secret represents a secret managed by the libvirt daemon. // Secret represents a secret managed by the libvirt daemon.
type Secret struct { // type Secret struct {
UUID [constants.UUIDSize]byte // UUID [constants.UUIDSize]byte
UsageType SecretUsageType // UsageType SecretUsageType
UsageID string // UsageID string
} // }
// StoragePool represents a storage pool as seen by libvirt. // StoragePool represents a storage pool as seen by libvirt.
type StoragePool struct { // type StoragePool struct {
Name string // Name string
UUID [constants.UUIDSize]byte // UUID [constants.UUIDSize]byte
} // }
// qemuError represents a QEMU process error. // qemuError represents a QEMU process error.
type qemuError struct { type qemuError struct {
@ -140,42 +140,42 @@ const (
// 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. This is defined as an interface, and // typed parameters to libvirt functions. This is defined as an interface, and
// implemented by TypedParam... concrete types. // implemented by TypedParam... concrete types.
type TypedParam interface { // type TypedParam interface {
Field() string // Field() string
Value() interface{} // Value() interface{}
} // }
// TypedParamInt contains a 32-bit signed integer. // TypedParamInt contains a 32-bit signed integer.
type TypedParamInt struct { // type TypedParamInt struct {
Fld string // Fld string
PType int32 // PType int32
Padding [4]byte // Padding [4]byte
Val int32 // Val int32
} // }
// Field returns the field name, a string name for the parameter. // Field returns the field name, a string name for the parameter.
func (tp *TypedParamInt) Field() string { // func (tp *TypedParamInt) Field() string {
return tp.Fld // return tp.Fld
} // }
// Value returns the value for the typed parameter, as an empty interface. // Value returns the value for the typed parameter, as an empty interface.
func (tp *TypedParamInt) Value() interface{} { // func (tp *TypedParamInt) Value() interface{} {
return tp.Val // return tp.Val
} // }
// NewTypedParamInt returns a TypedParam encoding for an int. // NewTypedParamInt returns a TypedParam encoding for an int.
func NewTypedParamInt(name string, v int32) *TypedParamInt { // 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 := TypedParamInt{ // tp := TypedParamInt{
Fld: name, // Fld: name,
PType: TypeParamInt, // PType: TypeParamInt,
Val: v, // Val: v,
} // }
return &tp // return &tp
} // }
// TypedParamULongLong contains a 64-bit unsigned integer. // TypedParamULongLong contains a 64-bit unsigned integer.
type TypedParamULongLong struct { type TypedParamULongLong struct {
@ -226,17 +226,17 @@ func (tp *TypedParamString) Value() interface{} {
} }
// NewTypedParamString returns a typed parameter containing the passed string. // NewTypedParamString returns a typed parameter containing the passed string.
func NewTypedParamString(name string, v string) TypedParam { // func NewTypedParamString(name string, v string) TypedParam {
if len(name) > constants.TypedParamFieldLength { // if len(name) > constants.TypedParamFieldLength {
name = name[:constants.TypedParamFieldLength] // name = name[:constants.TypedParamFieldLength]
} // }
tp := TypedParamString{ // tp := TypedParamString{
Fld: name, // Fld: name,
PType: TypeParamString, // PType: TypeParamString,
Val: v, // Val: v,
} // }
return &tp // return &tp
} // }
const ( const (
// DomainXMLFlagSecure dumps XML with sensitive information included. // DomainXMLFlagSecure dumps XML with sensitive information included.
@ -507,10 +507,10 @@ const (
) )
// DomainMemoryStat specifies memory stats of the domain // DomainMemoryStat specifies memory stats of the domain
type DomainMemoryStat struct { // type DomainMemoryStat struct {
Tag DomainMemoryStatTag // Tag DomainMemoryStatTag
Val uint64 // Val uint64
} // }
// Capabilities returns an XML document describing the host's capabilties. // Capabilities returns an XML document describing the host's capabilties.
func (l *Libvirt) Capabilities() ([]byte, error) { func (l *Libvirt) Capabilities() ([]byte, error) {
@ -596,76 +596,76 @@ func (l *Libvirt) Domains() ([]Domain, error) {
} }
// DomainCreateWithFlags starts specified domain with flags // DomainCreateWithFlags starts specified domain with flags
func (l *Libvirt) DomainCreateWithFlags(dom string, flags DomainCreateFlags) error { // func (l *Libvirt) DomainCreateWithFlags(dom string, flags DomainCreateFlags) error {
d, err := l.lookup(dom) // d, err := l.lookup(dom)
if err != nil { // if err != nil {
return err // return err
} // }
req := struct { // req := struct {
Domain Domain // Domain Domain
Flags DomainCreateFlags // Flags DomainCreateFlags
}{ // }{
Domain: *d, // Domain: *d,
Flags: flags, // Flags: flags,
} // }
//
buf, err := encode(&req) // buf, err := encode(&req)
if err != nil { // if err != nil {
return err // return err
} // }
resp, err := l.request(constants.ProcDomainCreateWithFlags, constants.Program, &buf) // resp, err := l.request(constants.ProcDomainCreateWithFlags, constants.Program, &buf)
if err != nil { // if err != nil {
return err // return err
} // }
r := <-resp // r := <-resp
if r.Status != StatusOK { // if r.Status != StatusOK {
return decodeError(r.Payload) // return decodeError(r.Payload)
} // }
return nil // return nil
} // }
// DomainMemoryStats returns memory stats of the domain managed by libvirt. // DomainMemoryStats returns memory stats of the domain managed by libvirt.
func (l *Libvirt) DomainMemoryStats(dom string) ([]DomainMemoryStat, error) { // func (l *Libvirt) DomainMemoryStats(dom string) ([]DomainMemoryStat, error) {
//
d, err := l.lookup(dom) // d, err := l.lookup(dom)
if err != nil { // if err != nil {
return nil, err // return nil, err
} // }
//
req := struct { // req := struct {
Domain Domain // Domain Domain
MaxStats uint32 // MaxStats uint32
Flags uint32 // Flags uint32
}{ // }{
Domain: *d, // Domain: *d,
MaxStats: 8, // MaxStats: 8,
Flags: 0, // Flags: 0,
} // }
//
buf, err := encode(&req) // buf, err := encode(&req)
if err != nil { // if err != nil {
return nil, err // return nil, err
} // }
//
resp, err := l.request(constants.ProcDomainMemoryStats, constants.Program, &buf) // resp, err := l.request(constants.ProcDomainMemoryStats, constants.Program, &buf)
if err != nil { // if err != nil {
return nil, err // return nil, err
} // }
//
r := <-resp // r := <-resp
//
result := struct { // result := struct {
DomainMemoryStats []DomainMemoryStat // DomainMemoryStats []DomainMemoryStat
}{} // }{}
//
dec := xdr.NewDecoder(bytes.NewReader(r.Payload)) // dec := xdr.NewDecoder(bytes.NewReader(r.Payload))
_, err = dec.Decode(&result) // _, err = dec.Decode(&result)
if err != nil { // if err != nil {
return nil, err // return nil, err
} // }
//
return result.DomainMemoryStats, nil // return result.DomainMemoryStats, nil
} // }
// DomainState returns state of the domain managed by libvirt. // DomainState returns state of the domain managed by libvirt.
func (l *Libvirt) DomainState(dom string) (DomainState, error) { func (l *Libvirt) DomainState(dom string) (DomainState, error) {
@ -678,7 +678,7 @@ func (l *Libvirt) DomainState(dom string) (DomainState, error) {
Domain Domain Domain Domain
Flags uint32 Flags uint32
}{ }{
Domain: *d, Domain: d,
Flags: 0, Flags: 0,
} }
@ -728,7 +728,7 @@ func (l *Libvirt) Events(dom string) (<-chan DomainEvent, error) {
Flags [2]byte Flags [2]byte
}{ }{
Padding: [4]byte{0x0, 0x0, 0x1, 0x0}, Padding: [4]byte{0x0, 0x0, 0x1, 0x0},
Domain: *d, Domain: d,
Event: [2]byte{0x0, 0x0}, Event: [2]byte{0x0, 0x0},
Flags: [2]byte{0x0, 0x0}, Flags: [2]byte{0x0, 0x0},
} }
@ -801,7 +801,7 @@ func (l *Libvirt) Migrate(dom string, dest string, flags MigrateFlags) error {
CookieIn uint32 CookieIn uint32
Flags MigrateFlags Flags MigrateFlags
}{ }{
Domain: *d, Domain: d,
Padding: [4]byte{0x0, 0x0, 0x0, 0x1}, Padding: [4]byte{0x0, 0x0, 0x0, 0x1},
DestinationURI: dest, DestinationURI: dest,
RemoteParameters: 0, RemoteParameters: 0,
@ -844,7 +844,7 @@ func (l *Libvirt) MigrateSetMaxSpeed(dom string, speed int64) error {
Flags uint32 Flags uint32
}{ }{
Padding: [4]byte{0x0, 0x0, 0x1, 0x0}, Padding: [4]byte{0x0, 0x0, 0x1, 0x0},
Domain: *d, Domain: d,
Bandwidth: speed, Bandwidth: speed,
} }
@ -880,7 +880,7 @@ func (l *Libvirt) Run(dom string, cmd []byte) ([]byte, error) {
Command []byte Command []byte
Flags uint32 Flags uint32
}{ }{
Domain: *d, Domain: d,
Command: cmd, Command: cmd,
Flags: 0, Flags: 0,
} }
@ -959,7 +959,7 @@ func (l *Libvirt) Secrets() ([]Secret, error) {
// StoragePool returns the storage pool associated with the provided name. // StoragePool returns the storage pool associated with the provided name.
// An error is returned if the requested storage pool is not found. // An error is returned if the requested storage pool is not found.
func (l *Libvirt) StoragePool(name string) (*StoragePool, error) { func (l *Libvirt) StoragePool(name string) (StoragePool, error) {
req := struct { req := struct {
Name string Name string
}{ }{
@ -991,41 +991,41 @@ func (l *Libvirt) StoragePool(name string) (*StoragePool, error) {
return nil, err return nil, err
} }
return &result.Pool, nil return result.Pool, nil
} }
// StoragePoolRefresh refreshes the storage pool specified by name. // StoragePoolRefresh refreshes the storage pool specified by name.
func (l *Libvirt) StoragePoolRefresh(name string) error { // func (l *Libvirt) StoragePoolRefresh(name string) error {
pool, err := l.StoragePool(name) // pool, err := l.StoragePool(name)
if err != nil { // if err != nil {
return err // return err
} // }
//
req := struct { // req := struct {
Pool StoragePool // Pool StoragePool
Flags uint32 // Flags uint32
}{ // }{
Pool: *pool, // Pool: *pool,
Flags: 0, // unused per libvirt source, callers should pass 0 // Flags: 0, // unused per libvirt source, callers should pass 0
} // }
//
buf, err := encode(&req) // buf, err := encode(&req)
if err != nil { // if err != nil {
return err // return err
} // }
//
resp, err := l.request(constants.ProcStoragePoolRefresh, constants.Program, &buf) // resp, err := l.request(constants.ProcStoragePoolRefresh, constants.Program, &buf)
if err != nil { // if err != nil {
return err // return err
} // }
//
r := <-resp // r := <-resp
if r.Status != StatusOK { // if r.Status != StatusOK {
return decodeError(r.Payload) // return decodeError(r.Payload)
} // }
//
return nil // return nil
} // }
// StoragePools returns a list of defined storage pools. Pools are filtered by // StoragePools returns a list of defined storage pools. Pools are filtered by
// the provided flags. See StoragePools*. // the provided flags. See StoragePools*.
@ -1081,7 +1081,7 @@ func (l *Libvirt) Undefine(dom string, flags UndefineFlags) error {
Domain Domain Domain Domain
Flags UndefineFlags Flags UndefineFlags
}{ }{
Domain: *d, Domain: d,
Flags: flags, Flags: flags,
} }
@ -1117,7 +1117,7 @@ func (l *Libvirt) Destroy(dom string, flags DestroyFlags) error {
Domain Domain Domain Domain
Flags DestroyFlags Flags DestroyFlags
}{ }{
Domain: *d, Domain: d,
Flags: flags, Flags: flags,
} }
@ -1151,7 +1151,7 @@ func (l *Libvirt) XML(dom string, flags DomainXMLFlags) ([]byte, error) {
Domain Domain Domain Domain
Flags DomainXMLFlags Flags DomainXMLFlags
}{ }{
Domain: *d, Domain: d,
Flags: flags, Flags: flags,
} }
@ -1255,7 +1255,7 @@ func (l *Libvirt) Shutdown(dom string, flags ShutdownFlags) error {
Domain Domain Domain Domain
Flags ShutdownFlags Flags ShutdownFlags
}{ }{
Domain: *d, Domain: d,
Flags: flags, Flags: flags,
} }
@ -1289,7 +1289,7 @@ func (l *Libvirt) Reboot(dom string, flags RebootFlags) error {
Domain Domain Domain Domain
Flags RebootFlags Flags RebootFlags
}{ }{
Domain: *d, Domain: d,
Flags: flags, Flags: flags,
} }
@ -1322,7 +1322,7 @@ func (l *Libvirt) Reset(dom string) error {
Domain Domain Domain Domain
Flags uint32 Flags uint32
}{ }{
Domain: *d, Domain: d,
Flags: 0, Flags: 0,
} }
@ -1405,14 +1405,15 @@ func (l *Libvirt) SetBlockIOTune(dom string, disk string, limits ...BlockLimit)
Params []TypedParam Params []TypedParam
Flags DomainAffectFlags Flags DomainAffectFlags
}{ }{
Domain: *d, Domain: d,
Disk: disk, Disk: disk,
Flags: FlagDomainAffectLive, Flags: FlagDomainAffectLive,
} }
for _, limit := range limits { for _, limit := range limits {
tp := NewTypedParamULongLong(limit.Name, limit.Value) tpval := NewTypedParamValueUllong(limit.Value)
payload.Params = append(payload.Params, tp) tp := &TypedParam{Field: limit.Name, Value: tpval}
payload.Params = append(payload.Params, *tp)
} }
buf, err := encode(&payload) buf, err := encode(&payload)
@ -1446,7 +1447,7 @@ func (l *Libvirt) GetBlockIOTune(dom string, disk string) ([]BlockLimit, error)
ParamCount uint32 ParamCount uint32
Flags DomainAffectFlags Flags DomainAffectFlags
}{ }{
Domain: *d, Domain: d,
Disk: []string{disk}, Disk: []string{disk},
ParamCount: 32, ParamCount: 32,
Flags: FlagTypedParamStringOkay, Flags: FlagTypedParamStringOkay,
@ -1516,7 +1517,7 @@ func (l *Libvirt) GetBlockIOTune(dom string, disk string) ([]BlockLimit, error)
} }
// lookup returns a domain as seen by libvirt. // lookup returns a domain as seen by libvirt.
func (l *Libvirt) lookup(name string) (*Domain, error) { func (l *Libvirt) lookup(name string) (Domain, error) {
payload := struct { payload := struct {
Name string Name string
}{name} }{name}
@ -1538,7 +1539,8 @@ func (l *Libvirt) lookup(name string) (*Domain, error) {
dec := xdr.NewDecoder(bytes.NewReader(r.Payload)) dec := xdr.NewDecoder(bytes.NewReader(r.Payload))
var d Domain // var d Domain
var d NonnullDomain
_, err = dec.Decode(&d) _, err = dec.Decode(&d)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -107,7 +107,7 @@ func TestDomains(t *testing.T) {
for i, d := range domains { for i, d := range domains {
wantID := i + 1 wantID := i + 1
if d.ID != wantID { if d.ID != int32(wantID) {
t.Errorf("expected domain ID %q, got %q", wantID, d.ID) t.Errorf("expected domain ID %q, got %q", wantID, d.ID)
} }
@ -148,17 +148,27 @@ func TestDomainMemoryStats(t *testing.T) {
}, },
} }
gotDomainMemoryStats, err := l.DomainMemoryStats("test") d, err := l.lookup("test")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
gotDomainMemoryStats, err := l.DomainMemoryStats(*d, 8, 0)
if err != nil {
t.Error(err)
}
t.Log(gotDomainMemoryStats)
if len(gotDomainMemoryStats) == 0 {
t.Error("No memory stats returned!")
}
for i := range wantDomainMemoryStats { for i := range wantDomainMemoryStats {
if wantDomainMemoryStats[i] != gotDomainMemoryStats[i] { if wantDomainMemoryStats[i] != gotDomainMemoryStats[i] {
t.Errorf("expected domain memory stat %v, got %v", wantDomainMemoryStats[i], gotDomainMemoryStats[i]) t.Errorf("expected domain memory stat %v, got %v", wantDomainMemoryStats[i], gotDomainMemoryStats[i])
} }
} }
} }
func TestEvents(t *testing.T) { func TestEvents(t *testing.T) {
@ -265,7 +275,7 @@ func TestSecrets(t *testing.T) {
} }
s := secrets[0] s := secrets[0]
wantType := SecretUsageTypeVolume wantType := int32(SecretUsageTypeVolume)
if s.UsageType != wantType { if s.UsageType != wantType {
t.Errorf("expected usage type %d, got %d", wantType, s.UsageType) t.Errorf("expected usage type %d, got %d", wantType, s.UsageType)
} }
@ -347,7 +357,11 @@ func TestStoragePoolRefresh(t *testing.T) {
conn := libvirttest.New() conn := libvirttest.New()
l := New(conn) l := New(conn)
err := l.StoragePoolRefresh("default") pool, err := l.StoragePool("default")
if err != nil {
t.Error(err)
}
err = l.StoragePoolRefresh(*pool, 0)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -403,8 +417,12 @@ func TestDomainCreateWithFlags(t *testing.T) {
conn := libvirttest.New() conn := libvirttest.New()
l := New(conn) l := New(conn)
var flags DomainCreateFlags d, err := l.lookup("test")
if err := l.DomainCreateWithFlags("test", flags); err != nil { if err != nil {
t.Fatalf("failed to lookup domain: %v", err)
}
var flags uint32
if _, err := l.DomainCreateWithFlags(*d, flags); err != nil {
t.Fatalf("unexpected create error: %v", err) t.Fatalf("unexpected create error: %v", err)
} }
} }

View File

@ -106,7 +106,7 @@ var (
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
} }
testDomain = Domain{ testDomain = &NonnullDomain{
Name: "test-domain", Name: "test-domain",
UUID: testUUID, UUID: testUUID,
ID: 1, ID: 1,
@ -177,7 +177,7 @@ func TestDecodeEvent(t *testing.T) {
t.Errorf("expected uuid:\t%x, got\n\t\t\t%x", expUUID, e.Domain.UUID) t.Errorf("expected uuid:\t%x, got\n\t\t\t%x", expUUID, e.Domain.UUID)
} }
expID := 14 expID := int32(14)
if e.Domain.ID != expID { if e.Domain.ID != expID {
t.Errorf("expected id %d, got %d", expID, e.Domain.ID) t.Errorf("expected id %d, got %d", expID, e.Domain.ID)
} }