Merge pull request #63 from YorikSar/streams

Add streams support to libvirt RPC API
This commit is contained in:
Geoff Hickey 2018-05-08 18:10:14 -04:00 committed by GitHub
commit 17c24de803
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1319 additions and 998 deletions

View File

@ -17,3 +17,4 @@ Simarpreet Singh <simar@linux.com>
Alexander Polyakov <apolyakov@beget.com>
Amanda Andrade <amanda.andrade@serpro.gov.br>
Geoff Hickey <ghickey@digitalocean.com>
Yuriy Taraday <yorik.sar@gmail.com>

View File

@ -159,13 +159,21 @@ type Case struct {
// Proc holds information about a libvirt procedure the parser has found.
type Proc struct {
Num int64 // The libvirt procedure number.
Name string // The name of the go func.
LVName string // The name of the libvirt proc this wraps.
Args []Decl // The contents of the args struct for this procedure.
Ret []Decl // The contents of the ret struct for this procedure.
ArgsStruct string // The name of the args struct for this procedure.
RetStruct string // The name of the ret struct for this procedure.
Num int64 // The libvirt procedure number.
Name string // The name of the go func.
LVName string // The name of the libvirt proc this wraps.
Args []Decl // The contents of the args struct for this procedure.
Ret []Decl // The contents of the ret struct for this procedure.
ArgsStruct string // The name of the args struct for this procedure.
RetStruct string // The name of the ret struct for this procedure.
ReadStreamIdx int // The index of read stream in function argument list
WriteStreamIdx int // The index of read stream in function argument list
}
// ProcMeta holds information from annotations attached to a libvirt procedure
type ProcMeta struct {
ReadStream int
WriteStream int
}
type structStack []*Structure
@ -552,7 +560,31 @@ func AddEnumVal(name, val string) error {
if err != nil {
return fmt.Errorf("invalid enum value %v = %v", name, val)
}
return addEnumVal(name, ev)
return addEnumVal(name, ev, nil)
}
// AddEnumValMeta will add a new enum value with attached metadata to the list.
// Metadata is parsed from annotations in libvirt RPC description file that are
// in block comment preceding every function in enum, it looks like this:
// /**
// * @generate: both
// * @readstream: 1
// * @sparseflag: VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM
// * @acl: storage_vol:data_read
// */
// See full description of possible annotations in libvirt's src/remote/remote_protocol.x
// at the top of remote_procedure enum.
// We're parsing only @readstream and @writestream annotations at the moment.
func AddEnumValMeta(name, val, meta string) error {
ev, err := parseNumber(val)
if err != nil {
return fmt.Errorf("invalid enum value %v = %v", name, val)
}
metaObj, err := parseMeta(meta)
if err != nil {
return fmt.Errorf("invalid metadata for enum value %v: %v", name, err)
}
return addEnumVal(name, ev, metaObj)
}
// AddEnumAutoVal adds an enum to the list, using the automatically-incremented
@ -560,14 +592,14 @@ func AddEnumVal(name, val string) error {
// explicit value.
func AddEnumAutoVal(name string) error {
CurrentEnumVal++
return addEnumVal(name, CurrentEnumVal)
return addEnumVal(name, CurrentEnumVal, nil)
}
func addEnumVal(name string, val int64) error {
func addEnumVal(name string, val int64, meta *ProcMeta) error {
goname := constNameTransform(name)
Gen.EnumVals = append(Gen.EnumVals, ConstItem{goname, name, fmt.Sprintf("%d", val)})
CurrentEnumVal = val
addProc(goname, name, val)
addProc(goname, name, val, meta)
return nil
}
@ -584,12 +616,16 @@ func AddConst(name, val string) error {
// 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(goname, lvname string, val int64) {
func addProc(goname, lvname string, val int64, meta *ProcMeta) {
if !strings.HasPrefix(goname, "Proc") {
return
}
goname = goname[4:]
proc := &Proc{Num: val, Name: goname, LVName: lvname}
proc := &Proc{Num: val, Name: goname, LVName: lvname, ReadStreamIdx: -1, WriteStreamIdx: -1}
if meta != nil {
proc.ReadStreamIdx = meta.ReadStream
proc.WriteStreamIdx = meta.WriteStream
}
Gen.Procs = append(Gen.Procs, *proc)
}
@ -605,6 +641,41 @@ func parseNumber(val string) (int64, error) {
return n, err
}
// parseMeta parses procedure metadata to simple string mapping
func parseMeta(meta string) (*ProcMeta, error) {
res := &ProcMeta{
ReadStream: -1,
WriteStream: -1,
}
for _, line := range strings.Split(meta, "\n") {
atInd := strings.Index(line, "@")
if atInd == -1 {
// Should be only first and last line of comment
continue
}
spl := strings.SplitN(line[atInd+1:], ":", 2)
if len(spl) != 2 {
return nil, fmt.Errorf("invalid annotation: %s", meta)
}
spl[1] = strings.Trim(spl[1], " ")
switch spl[0] {
case "readstream":
var err error
res.ReadStream, err = strconv.Atoi(spl[1])
if err != nil {
return nil, fmt.Errorf("invalid value for readstream: %s", spl[1])
}
case "writestream":
var err error
res.WriteStream, err = strconv.Atoi(spl[1])
if err != nil {
return nil, fmt.Errorf("invalid value for writestream: %s", spl[1])
}
}
}
return res, nil
}
// StartStruct is called from the parser when a struct definition is found, but
// before the member declarations are processed.
func StartStruct(name string) {

View File

@ -259,12 +259,19 @@ func lexText(l *Lexer) stateFn {
// lexBlockComment is used when we find a comment marker '/*' in the input.
func lexBlockComment(l *Lexer) stateFn {
// Double star is used only at the start of metadata comments
metadataComment := strings.HasPrefix(l.input[l.pos:], "/**")
for {
if strings.HasPrefix(l.input[l.pos:], "*/") {
// Found the end. Advance past the '*/' and discard the comment body.
// Found the end. Advance past the '*/' and discard the comment body
// unless it's a metadata comment
l.next()
l.next()
l.ignore()
if metadataComment {
l.emit(METADATACOMMENT)
} else {
l.ignore()
}
return lexText
}
if l.next() == eof {

View File

@ -23,6 +23,7 @@ package libvirt
import (
"bytes"
"fmt"
"io"
"github.com/davecgh/go-xdr/xdr2"
"github.com/digitalocean/go-libvirt/internal/constants"
@ -126,9 +127,15 @@ func decodeTypedParams(dec *xdr.Decoder) ([]TypedParam, error) {
return params, nil
}
{{range .Procs}}
{{range $proc := .Procs}}
// {{.Name}} is the go wrapper for {{.LVName}}.
func (l *Libvirt) {{.Name}}({{range $ix, $arg := .Args}}{{if $ix}}, {{end}}{{.Name}} {{.Type}}{{end}}) ({{range .Ret}}r{{.Name}} {{.Type}}, {{end}}err error) {
func (l *Libvirt) {{.Name}}(
{{- range $ix, $arg := .Args}}
{{- if (eq $ix $proc.WriteStreamIdx)}}{{if $ix}}, {{end}}outStream io.Reader{{end}}
{{- if (eq $ix $proc.ReadStreamIdx)}}{{if $ix}}, {{end}}inStream io.Writer{{end}}
{{- if $ix}}, {{end}}{{.Name}} {{.Type}}
{{- end -}}
) ({{range .Ret}}r{{.Name}} {{.Type}}, {{end}}err error) {
var buf []byte
{{if .ArgsStruct}}
args := {{.ArgsStruct}} {
@ -141,7 +148,10 @@ func (l *Libvirt) {{.Name}}({{range $ix, $arg := .Args}}{{if $ix}}, {{end}}{{.Na
}
{{end}}
{{if .RetStruct}} var r response{{end}}
{{if .RetStruct}}r{{else}}_{{end}}, err = l.request({{.Num}}, constants.Program, buf)
{{if .RetStruct}}r{{else}}_{{end}}, err = l.requestStream({{.Num}}, constants.Program, buf,
{{- if (ne .WriteStreamIdx -1)}} outStream,{{else}} nil,{{end}}
{{- if (ne .ReadStreamIdx -1)}} inStream{{else}} nil{{end -}}
)
if err != nil {
return
}

View File

@ -56,6 +56,7 @@ import (
%token IDENTIFIER CONSTANT ERROR
// RPCL additional tokens:
%token PROGRAM VERSION
%token METADATACOMMENT
%%
@ -99,6 +100,13 @@ enum_value
return 1
}
}
| METADATACOMMENT enum_value_ident '=' value {
err := AddEnumValMeta($2.val, $4.val, $1.val)
if err != nil {
yylex.Error(err.Error())
return 1
}
}
| enum_value_ident '=' value {
err := AddEnumVal($1.val, $3.val)
if err != nil {

View File

@ -59,6 +59,7 @@ const CONSTANT = 57366
const ERROR = 57367
const PROGRAM = 57368
const VERSION = 57369
const METADATACOMMENT = 57370
var yyToknames = [...]string{
"$end",
@ -88,6 +89,7 @@ var yyToknames = [...]string{
"ERROR",
"PROGRAM",
"VERSION",
"METADATACOMMENT",
"';'",
"'{'",
"'}'",
@ -108,7 +110,7 @@ const yyEofCode = 1
const yyErrCode = 2
const yyInitialStackSize = 16
//line sunrpc.y:259
//line sunrpc.y:267
//line yacctab:1
var yyExca = [...]int{
@ -119,106 +121,107 @@ var yyExca = [...]int{
const yyPrivate = 57344
const yyLast = 148
const yyLast = 153
var yyAct = [...]int{
84, 77, 36, 111, 103, 76, 61, 67, 32, 129,
55, 126, 128, 100, 37, 117, 85, 86, 78, 63,
98, 97, 73, 31, 74, 69, 131, 115, 71, 89,
41, 94, 72, 62, 40, 10, 39, 43, 42, 13,
30, 118, 14, 38, 107, 48, 49, 50, 51, 47,
90, 11, 79, 64, 10, 70, 106, 96, 13, 54,
12, 14, 52, 29, 134, 127, 119, 108, 91, 75,
80, 15, 16, 110, 87, 88, 85, 86, 59, 60,
63, 93, 83, 48, 49, 50, 51, 92, 95, 58,
82, 27, 25, 23, 20, 102, 18, 99, 2, 105,
101, 46, 8, 66, 45, 7, 109, 44, 4, 104,
113, 105, 114, 116, 120, 28, 122, 81, 8, 68,
123, 7, 26, 124, 4, 121, 125, 112, 130, 53,
24, 132, 133, 65, 22, 35, 34, 33, 21, 19,
57, 56, 17, 9, 6, 5, 3, 1,
86, 79, 36, 115, 107, 78, 62, 32, 68, 55,
57, 133, 130, 132, 104, 121, 87, 88, 80, 64,
37, 102, 75, 31, 76, 101, 114, 135, 119, 72,
92, 41, 97, 89, 63, 40, 10, 39, 43, 42,
13, 73, 30, 14, 38, 122, 48, 49, 50, 51,
47, 111, 93, 81, 71, 11, 110, 138, 10, 65,
99, 54, 13, 52, 12, 14, 29, 131, 123, 74,
77, 112, 94, 59, 82, 15, 90, 91, 58, 70,
16, 64, 85, 96, 87, 88, 60, 61, 95, 84,
100, 98, 48, 49, 50, 51, 113, 59, 106, 27,
103, 25, 109, 105, 23, 20, 18, 67, 46, 8,
108, 45, 7, 44, 4, 109, 2, 120, 124, 117,
126, 118, 83, 69, 127, 8, 26, 128, 7, 125,
4, 129, 134, 28, 116, 136, 137, 53, 24, 66,
22, 35, 34, 33, 21, 19, 56, 17, 9, 6,
5, 3, 1,
}
var yyPact = [...]int{
45, -1000, -1000, 44, -1000, -1000, -1000, -1000, -1000, -1000,
73, 71, -1000, 70, 69, 68, 45, 34, -1000, 8,
-1000, 26, 33, -1000, -1000, -1000, 30, -1000, -1000, 66,
55, -1000, -1000, -1000, -1000, -1000, -4, -1000, 64, -1000,
49, -1000, -1000, 51, -1000, -1000, -1000, -1000, -1000, -1000,
83, 82, -1000, 81, 78, 76, 49, 36, -1000, 9,
-1000, 27, 33, -1000, -1000, -1000, 31, -1000, -1000, 50,
63, -1000, -1000, -1000, -1000, -1000, -4, -1000, 73, -1000,
-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-1000, -1000, -1000, 89, -2, 25, -3, 0, -1000, -1000,
-1000, -11, 57, -1000, -1000, 26, -20, 22, 42, 67,
-1000, 66, 53, 53, -7, -1000, 20, 40, 26, -1,
-2, 28, -1000, -1000, -1000, -1000, -1000, -13, -16, -1000,
-1000, 26, -26, 57, 53, -1000, 26, -1000, -1000, -1000,
27, -1000, -1000, 14, 39, 50, 105, -5, 26, -23,
-1000, 11, 38, 53, -1000, 53, -1000, 26, -1000, 105,
-1000, -29, 37, -27, -1000, -31, 26, -1000, -6, 26,
-1000, 53, -1000, 36, -1000,
-1000, -1000, -1000, 93, 52, 23, -3, 8, 74, -1000,
-1000, -1000, -12, 58, -1000, -1000, 27, -21, 22, 45,
66, -1000, 50, 61, 0, 61, -7, -1000, 21, 43,
27, -1, 52, 30, -1000, -1000, -1000, -1000, -1000, 61,
-10, -16, -1000, -1000, 27, -26, 58, 61, -1000, 27,
-1000, -1000, -1000, -1000, 26, -1000, -1000, 20, 42, 3,
114, -5, 27, -24, -1000, 14, 39, 61, -1000, 61,
-1000, 27, -1000, 114, -1000, -29, 38, -27, -1000, -30,
27, -1000, -6, 27, -1000, 61, -1000, 28, -1000,
}
var yyPgo = [...]int{
0, 147, 98, 0, 146, 107, 145, 144, 104, 101,
143, 142, 10, 141, 140, 139, 138, 1, 8, 137,
136, 135, 2, 6, 14, 134, 133, 5, 130, 129,
3, 127, 126, 125, 122, 7, 119, 117, 4, 109,
106,
0, 152, 116, 0, 151, 113, 150, 149, 111, 108,
148, 147, 9, 146, 10, 145, 144, 1, 7, 143,
142, 141, 2, 6, 20, 140, 139, 5, 138, 137,
3, 134, 131, 129, 126, 8, 123, 122, 4, 110,
96,
}
var yyR1 = [...]int{
0, 1, 3, 3, 2, 2, 4, 4, 4, 4,
4, 4, 5, 12, 12, 13, 13, 11, 14, 6,
6, 15, 16, 7, 17, 17, 17, 17, 18, 22,
4, 4, 5, 12, 12, 13, 13, 13, 11, 14,
6, 6, 15, 16, 7, 17, 17, 17, 17, 18,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
24, 24, 24, 24, 23, 19, 20, 20, 21, 26,
8, 25, 27, 27, 29, 9, 28, 30, 30, 32,
31, 33, 31, 10, 34, 35, 35, 36, 37, 38,
38, 39, 40,
22, 24, 24, 24, 24, 23, 19, 20, 20, 21,
26, 8, 25, 27, 27, 29, 9, 28, 30, 30,
32, 31, 33, 31, 10, 34, 35, 35, 36, 37,
38, 38, 39, 40,
}
var yyR2 = [...]int{
0, 1, 1, 1, 2, 3, 1, 1, 1, 1,
1, 1, 5, 1, 3, 1, 3, 1, 1, 4,
4, 1, 0, 3, 1, 1, 1, 1, 2, 1,
2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 5, 5, 4, 3, 0,
6, 1, 2, 3, 0, 10, 1, 2, 3, 0,
5, 0, 4, 7, 1, 2, 3, 8, 1, 2,
3, 8, 1,
1, 1, 5, 1, 3, 1, 4, 3, 1, 1,
4, 4, 1, 0, 3, 1, 1, 1, 1, 2,
1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 5, 5, 4, 3,
0, 6, 1, 2, 3, 0, 10, 1, 2, 3,
0, 5, 0, 4, 7, 1, 2, 3, 8, 1,
2, 3, 8, 1,
}
var yyChk = [...]int{
-1000, -1, -2, -4, -5, -6, -7, -8, -9, -10,
9, 6, 15, 13, 16, 26, 28, -11, 23, -15,
23, -16, -25, 23, -28, 23, -34, 23, -2, 29,
32, -17, -18, -19, -20, -21, -22, -24, 17, 10,
9, 6, 15, 13, 16, 26, 29, -11, 23, -15,
23, -16, -25, 23, -28, 23, -34, 23, -2, 30,
33, -17, -18, -19, -20, -21, -22, -24, 17, 10,
8, 4, 12, 11, -5, -8, -9, 23, 19, 20,
21, 22, 29, -29, 29, -12, -13, -14, 23, 23,
24, -23, 37, 23, -24, -26, 14, -35, -36, 27,
30, 31, 32, 33, 35, -23, -27, -17, 38, 30,
28, -37, 23, -12, -3, 23, 24, -3, -3, 36,
30, 28, -18, -22, 32, -35, 29, 34, 36, -27,
39, -23, -3, -38, -39, -22, 29, 30, 28, -40,
23, -30, -31, 5, 7, 32, -38, 38, 30, 28,
-3, -33, -3, -22, -30, -32, 40, 28, 39, 40,
-17, 32, -17, -3, 28,
21, 22, 30, -29, 30, -12, -13, -14, 28, 23,
23, 24, -23, 38, 23, -24, -26, 14, -35, -36,
27, 31, 32, 33, -14, 34, 36, -23, -27, -17,
39, 31, 29, -37, 23, -12, -3, 23, 24, 33,
-3, -3, 37, 31, 29, -18, -22, 33, -35, 30,
-3, 35, 37, -27, 40, -23, -3, -38, -39, -22,
30, 31, 29, -40, 23, -30, -31, 5, 7, 33,
-38, 39, 31, 29, -3, -33, -3, -22, -30, -32,
41, 29, 40, 41, -17, 33, -17, -3, 29,
}
var yyDef = [...]int{
0, -2, 1, 0, 6, 7, 8, 9, 10, 11,
0, 0, 22, 0, 0, 0, 4, 0, 17, 0,
21, 0, 0, 51, 54, 56, 0, 64, 5, 0,
0, 23, 24, 25, 26, 27, 0, 29, 0, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 49, 0, 0, 0, 13, 15, 18, 19,
20, 28, 0, 44, 30, 0, 0, 0, 0, 0,
12, 0, 0, 0, 0, 48, 0, 0, 0, 0,
65, 0, 68, 14, 16, 2, 3, 0, 0, 47,
50, 52, 0, 0, 0, 66, 0, 45, 46, 53,
0, 28, 63, 0, 0, 0, 0, 0, 69, 0,
72, 0, 0, 0, 61, 0, 70, 0, 55, 57,
59, 0, 0, 0, 58, 0, 0, 67, 0, 0,
62, 0, 60, 0, 71,
0, 0, 23, 0, 0, 0, 4, 0, 18, 0,
22, 0, 0, 52, 55, 57, 0, 65, 5, 0,
0, 24, 25, 26, 27, 28, 0, 30, 0, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 50, 0, 0, 0, 13, 15, 0, 19,
20, 21, 29, 0, 45, 31, 0, 0, 0, 0,
0, 12, 0, 0, 0, 0, 0, 49, 0, 0,
0, 0, 66, 0, 69, 14, 17, 2, 3, 0,
0, 0, 48, 51, 53, 0, 0, 0, 67, 0,
16, 46, 47, 54, 0, 29, 64, 0, 0, 0,
0, 0, 70, 0, 73, 0, 0, 0, 62, 0,
71, 0, 56, 58, 60, 0, 0, 0, 59, 0,
0, 68, 0, 0, 63, 0, 61, 0, 72,
}
var yyTok1 = [...]int{
@ -226,21 +229,21 @@ var yyTok1 = [...]int{
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
38, 39, 37, 3, 31, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 40, 28,
35, 32, 36, 3, 3, 3, 3, 3, 3, 3,
39, 40, 38, 3, 32, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 41, 29,
36, 33, 37, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 33, 3, 34, 3, 3, 3, 3, 3, 3,
3, 34, 3, 35, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 29, 3, 30,
3, 3, 3, 30, 3, 31,
}
var yyTok2 = [...]int{
2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27,
22, 23, 24, 25, 26, 27, 28,
}
var yyTok3 = [...]int{
0,
@ -585,13 +588,13 @@ yydefault:
case 12:
yyDollar = yyS[yypt-5 : yypt+1]
//line sunrpc.y:86
//line sunrpc.y:87
{
StartEnum(yyDollar[2].val)
}
case 15:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:95
//line sunrpc.y:96
{
err := AddEnumAutoVal(yyDollar[1].val)
if err != nil {
@ -600,8 +603,18 @@ yydefault:
}
}
case 16:
yyDollar = yyS[yypt-4 : yypt+1]
//line sunrpc.y:103
{
err := AddEnumValMeta(yyDollar[2].val, yyDollar[4].val, yyDollar[1].val)
if err != nil {
yylex.Error(err.Error())
return 1
}
}
case 17:
yyDollar = yyS[yypt-3 : yypt+1]
//line sunrpc.y:102
//line sunrpc.y:110
{
err := AddEnumVal(yyDollar[1].val, yyDollar[3].val)
if err != nil {
@ -609,9 +622,9 @@ yydefault:
return 1
}
}
case 20:
case 21:
yyDollar = yyS[yypt-4 : yypt+1]
//line sunrpc.y:124
//line sunrpc.y:132
{
err := AddConst(yyDollar[2].val, yyDollar[4].val)
if err != nil {
@ -619,147 +632,147 @@ yydefault:
return 1
}
}
case 22:
case 23:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:138
//line sunrpc.y:146
{
StartTypedef()
}
case 28:
case 29:
yyDollar = yyS[yypt-2 : yypt+1]
//line sunrpc.y:149
//line sunrpc.y:157
{
AddDeclaration(yyDollar[2].val, yyDollar[1].val)
}
case 30:
case 31:
yyDollar = yyS[yypt-2 : yypt+1]
//line sunrpc.y:154
//line sunrpc.y:162
{
yyVAL.val = "u" + yyDollar[2].val
}
case 31:
case 32:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:155
//line sunrpc.y:163
{
yyVAL.val = "float32"
}
case 32:
case 33:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:156
//line sunrpc.y:164
{
yyVAL.val = "float64"
}
case 33:
case 34:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:157
//line sunrpc.y:165
{
yyVAL.val = "bool"
}
case 34:
case 35:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:158
//line sunrpc.y:166
{
yyVAL.val = "string"
}
case 35:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:159
{
yyVAL.val = "byte"
}
case 40:
case 36:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:167
{
yyVAL.val = "int64"
yyVAL.val = "byte"
}
case 41:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:168
//line sunrpc.y:175
{
yyVAL.val = "int32"
yyVAL.val = "int64"
}
case 42:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:169
//line sunrpc.y:176
{
yyVAL.val = "int16"
yyVAL.val = "int32"
}
case 43:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:170
//line sunrpc.y:177
{
yyVAL.val = "int16"
}
case 44:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:178
{
yyVAL.val = "int8"
}
case 45:
case 46:
yyDollar = yyS[yypt-5 : yypt+1]
//line sunrpc.y:178
//line sunrpc.y:186
{
AddFixedArray(yyDollar[2].val, yyDollar[1].val, yyDollar[4].val)
}
case 46:
case 47:
yyDollar = yyS[yypt-5 : yypt+1]
//line sunrpc.y:182
//line sunrpc.y:190
{
AddVariableArray(yyDollar[2].val, yyDollar[1].val, yyDollar[4].val)
}
case 47:
case 48:
yyDollar = yyS[yypt-4 : yypt+1]
//line sunrpc.y:183
//line sunrpc.y:191
{
AddVariableArray(yyDollar[2].val, yyDollar[1].val, "")
}
case 48:
case 49:
yyDollar = yyS[yypt-3 : yypt+1]
//line sunrpc.y:191
//line sunrpc.y:199
{
AddOptValue(yyDollar[3].val, yyDollar[1].val)
}
case 49:
case 50:
yyDollar = yyS[yypt-3 : yypt+1]
//line sunrpc.y:195
//line sunrpc.y:203
{
StartStruct(yyDollar[2].val)
}
case 50:
case 51:
yyDollar = yyS[yypt-6 : yypt+1]
//line sunrpc.y:195
//line sunrpc.y:203
{
AddStruct()
}
case 54:
case 55:
yyDollar = yyS[yypt-2 : yypt+1]
//line sunrpc.y:208
//line sunrpc.y:216
{
StartUnion(yyDollar[2].val)
}
case 55:
case 56:
yyDollar = yyS[yypt-10 : yypt+1]
//line sunrpc.y:208
//line sunrpc.y:216
{
AddUnion()
}
case 59:
case 60:
yyDollar = yyS[yypt-2 : yypt+1]
//line sunrpc.y:221
//line sunrpc.y:229
{
StartCase(yyDollar[2].val)
}
case 60:
case 61:
yyDollar = yyS[yypt-5 : yypt+1]
//line sunrpc.y:221
//line sunrpc.y:229
{
AddCase()
}
case 61:
case 62:
yyDollar = yyS[yypt-1 : yypt+1]
//line sunrpc.y:222
//line sunrpc.y:230
{
StartCase("default")
}
case 62:
case 63:
yyDollar = yyS[yypt-4 : yypt+1]
//line sunrpc.y:222
//line sunrpc.y:230
{
AddCase()
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,7 @@
package libvirt
import (
"bytes"
"encoding/xml"
"net"
"sync"
@ -252,6 +253,58 @@ func TestXMLIntegration(t *testing.T) {
}
}
func TestVolumeUploadDownloadIntegration(t *testing.T) {
testdata := []byte("Hello, world!")
l := New(testConn(t))
if err := l.Connect(); err != nil {
t.Error(err)
}
defer l.Disconnect()
pool, err := l.StoragePool("test")
if err != nil {
t.Fatal(err)
}
var volObj struct {
XMLName xml.Name `xml:"volume"`
Name string `xml:"name"`
Capacity struct {
Value uint64 `xml:",chardata"`
} `xml:"capacity"`
Target struct {
Format struct {
Type string `xml:"type,attr"`
} `xml:"format"`
} `xml:"target"`
}
volObj.Name = "testvol"
volObj.Capacity.Value = uint64(len(testdata))
volObj.Target.Format.Type = "raw"
xmlVol, err := xml.Marshal(volObj)
if err != nil {
t.Fatal(err)
}
vol, err := l.StorageVolCreateXML(pool, string(xmlVol), 0)
if err != nil {
t.Fatal(err)
}
defer l.StorageVolDelete(vol, 0)
err = l.StorageVolUpload(vol, bytes.NewBuffer(testdata), 0, 0, 0)
if err != nil {
t.Fatal(err)
}
var buf bytes.Buffer
err = l.StorageVolDownload(vol, &buf, 0, 0, 0)
if err != nil {
t.Fatal(err)
}
if bytes.Compare(testdata, buf.Bytes()) != 0 {
t.Fatal("download not what we uploaded")
}
}
// verify we're able to concurrently communicate with libvirtd.
// see: https://github.com/digitalocean/go-libvirt/pull/52
func Test_concurrentWrite(t *testing.T) {

118
rpc.go
View File

@ -174,10 +174,12 @@ func (l *Libvirt) callback(id uint32, res response) {
c, ok := l.callbacks[id]
l.cm.Unlock()
if ok {
// we close channel in deregister() so that we don't block here forever without receiver
defer func() {
recover()
}()
c <- res
}
l.deregister(id)
}
// route sends incoming packets to their listeners.
@ -274,11 +276,107 @@ func (l *Libvirt) deregister(id uint32) {
// returns response returned by server.
// if response is not OK, decodes error from it and returns it.
func (l *Libvirt) request(proc uint32, program uint32, payload []byte) (response, error) {
return l.requestStream(proc, program, payload, nil, nil)
}
func (l *Libvirt) processIncomingStream(c chan response, inStream io.Writer) (response, error) {
for {
resp, err := l.getResponse(c)
if err != nil {
return resp, err
}
// StatusOK here means end of stream
if resp.Status == StatusOK {
return resp, nil
}
// StatusError is handled in getResponse, so this is StatusContinue
// StatusContinue is valid here only for stream packets
// libvirtd breaks protocol and returns StatusContinue with empty Payload when stream finishes
if len(resp.Payload) == 0 {
return resp, nil
}
if inStream != nil {
_, err = inStream.Write(resp.Payload)
if err != nil {
return response{}, err
}
}
}
}
func (l *Libvirt) requestStream(proc uint32, program uint32, payload []byte, outStream io.Reader, inStream io.Writer) (response, error) {
serial := l.serial()
c := make(chan response)
l.register(serial, c)
defer l.deregister(serial)
err := l.sendPacket(serial, proc, program, payload, Call, StatusOK)
if err != nil {
return response{}, err
}
resp, err := l.getResponse(c)
if err != nil {
return resp, err
}
if outStream != nil {
abortOutStream := make(chan bool)
outStreamErr := make(chan error)
go func() {
outStreamErr <- l.sendStream(serial, proc, program, outStream, abortOutStream)
}()
// Even without incoming stream server sends confirmation once all data is received
resp, err = l.processIncomingStream(c, inStream)
if err != nil {
abortOutStream <- true
return resp, err
}
err = <-outStreamErr
if err != nil {
return response{}, err
}
} else if inStream != nil {
return l.processIncomingStream(c, inStream)
}
return resp, nil
}
func (l *Libvirt) sendStream(serial uint32, proc uint32, program uint32, stream io.Reader, abort chan bool) error {
// Keep total packet length under 4 MiB to follow possible limitation in libvirt server code
buf := make([]byte, 4*MiB-constants.HeaderSize)
for {
select {
case <-abort:
return l.sendPacket(serial, proc, program, nil, Stream, StatusError)
default:
}
n, err := stream.Read(buf)
if err != nil {
if err == io.EOF {
return l.sendPacket(serial, proc, program, nil, Stream, StatusOK)
}
// keep original error
err2 := l.sendPacket(serial, proc, program, nil, Stream, StatusError)
if err2 != nil {
return err2
}
return err
}
if n > 0 {
err = l.sendPacket(serial, proc, program, buf[:n], Stream, StatusContinue)
if err != nil {
return err
}
}
}
}
func (l *Libvirt) sendPacket(serial uint32, proc uint32, program uint32, payload []byte, typ uint32, status uint32) error {
size := constants.PacketLengthSize + constants.HeaderSize
if payload != nil {
size += len(payload)
@ -290,9 +388,9 @@ func (l *Libvirt) request(proc uint32, program uint32, payload []byte) (response
Program: program,
Version: constants.ProtocolVersion,
Procedure: proc,
Type: Call,
Type: typ,
Serial: serial,
Status: StatusOK,
Status: status,
},
}
@ -301,23 +399,23 @@ func (l *Libvirt) request(proc uint32, program uint32, payload []byte) (response
defer l.mu.Unlock()
err := binary.Write(l.w, binary.BigEndian, p)
if err != nil {
return response{}, err
return err
}
// write payload
if payload != nil {
err = binary.Write(l.w, binary.BigEndian, payload)
if err != nil {
return response{}, err
return err
}
}
if err := l.w.Flush(); err != nil {
return response{}, err
}
return l.w.Flush()
}
func (l *Libvirt) getResponse(c chan response) (response, error) {
resp := <-c
if resp.Status != StatusOK {
if resp.Status == StatusError {
return resp, decodeError(resp.Payload)
}

27
units.go Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2016 The go-libvirt Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This module provides different units of measurement to make other
// code more readable.
package libvirt
const (
// B - byte
B = 1
// KiB - kibibyte
KiB = 1024 * B
// MiB - mebibyte
MiB = 1024 * KiB
)