Merge pull request #7836 from 70k10/vncpassword

QEMU builder - implement VNC password functionality
This commit is contained in:
Megan Marsh 2019-07-16 16:37:49 -07:00 committed by GitHub
commit 2d02ea209d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 23388 additions and 11 deletions

View File

@ -117,6 +117,7 @@ type Config struct {
OutputDir string `mapstructure:"output_directory"`
QemuArgs [][]string `mapstructure:"qemuargs"`
QemuBinary string `mapstructure:"qemu_binary"`
QMPSocketPath string `mapstructure:"qmp_socket_path"`
ShutdownCommand string `mapstructure:"shutdown_command"`
SSHHostPortMin int `mapstructure:"ssh_host_port_min"`
SSHHostPortMax int `mapstructure:"ssh_host_port_max"`
@ -124,6 +125,7 @@ type Config struct {
VNCBindAddress string `mapstructure:"vnc_bind_address"`
VNCPortMin int `mapstructure:"vnc_port_min"`
VNCPortMax int `mapstructure:"vnc_port_max"`
VNCUsePassword bool `mapstructure:"vnc_use_password"`
VMName string `mapstructure:"vm_name"`
// These are deprecated, but we keep them around for BC
@ -344,6 +346,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(
errs, errors.New("ssh_host_port_min must be less than ssh_host_port_max"))
}
if b.config.SSHHostPortMin < 0 {
errs = packer.MultiErrorAppend(
errs, errors.New("ssh_host_port_min must be positive"))
@ -354,6 +357,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs, fmt.Errorf("vnc_port_min must be less than vnc_port_max"))
}
if b.config.VNCUsePassword && b.config.QMPSocketPath == "" {
socketName := fmt.Sprintf("%s.monitor", b.config.VMName)
b.config.QMPSocketPath = filepath.Join(b.config.OutputDir, socketName)
}
if b.config.QemuArgs == nil {
b.config.QemuArgs = make([][]string, 0)
}
@ -425,6 +433,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
steps = append(steps,
new(stepConfigureVNC),
steprun,
new(stepConfigureQMP),
&stepTypeBootCommand{},
)

View File

@ -4,6 +4,7 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
@ -598,3 +599,24 @@ func TestBuilderPrepare_QemuArgs(t *testing.T) {
t.Fatalf("bad: %#v", b.config.QemuArgs)
}
}
func TestBuilderPrepare_VNCPassword(t *testing.T) {
var b Builder
config := testConfig()
config["vnc_use_password"] = true
config["output_directory"] = "not-a-real-directory"
b = Builder{}
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
expected := filepath.Join("not-a-real-directory", "packer-foo.monitor")
if !reflect.DeepEqual(b.config.QMPSocketPath, expected) {
t.Fatalf("Bad QMP socket Path: %s", b.config.QMPSocketPath)
}
}

View File

@ -0,0 +1,89 @@
package qemu
import (
"context"
"fmt"
"log"
"time"
"github.com/digitalocean/go-qemu/qmp"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// This step configures the VM to enable the QMP listener.
//
// Uses:
// config *config
// ui packer.Ui
//
// Produces:
type stepConfigureQMP struct {
monitor *qmp.SocketMonitor
}
func (s *stepConfigureQMP) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui)
if !config.VNCUsePassword {
return multistep.ActionContinue
}
msg := fmt.Sprintf("QMP socket at: %s", config.QMPSocketPath)
ui.Say(msg)
log.Print(msg)
// Only initialize and open QMP when we have a use for it.
// Open QMP socket
var err error
var cmd []byte
var result []byte
s.monitor, err = qmp.NewSocketMonitor("unix", config.QMPSocketPath, 2*time.Second)
if err != nil {
err := fmt.Errorf("Error opening QMP socket: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
QMPMonitor := s.monitor
vncPassword := state.Get("vnc_password")
// Connect to QMP
// function automatically calls capabilities so is immediately ready for commands
err = QMPMonitor.Connect()
if err != nil {
err := fmt.Errorf("Error connecting to QMP socket: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
log.Printf("QMP socket open SUCCESS")
cmd = []byte(fmt.Sprintf("{ \"execute\": \"change-vnc-password\", \"arguments\": { \"password\": \"%s\" } }",
vncPassword))
result, err = QMPMonitor.Run(cmd)
if err != nil {
err := fmt.Errorf("Error connecting to QMP socket: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
msg = fmt.Sprintf("QMP Command: %s\nResult: %s", cmd, result)
log.Printf(msg)
// Put QMP monitor in statebag in case there is a use in a following step
// Uncomment for future case as it is unused for now
//state.Put("qmp_monitor", QMPMonitor)
return multistep.ActionContinue
}
func (s *stepConfigureQMP) Cleanup(multistep.StateBag) {
if s.monitor != nil {
err := s.monitor.Disconnect()
if err != nil {
log.Printf("failed to disconnect QMP: %v", err)
}
}
}

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"log"
"math/rand"
"github.com/hashicorp/packer/common/net"
"github.com/hashicorp/packer/helper/multistep"
@ -22,6 +23,21 @@ type stepConfigureVNC struct {
l *net.Listener
}
func VNCPassword() string {
length := int(8)
charSet := []byte("012345689abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
charSetLength := len(charSet)
password := make([]byte, length)
for i := 0; i < length; i++ {
password[i] = charSet[rand.Intn(charSetLength)]
}
return string(password)
}
func (s *stepConfigureVNC) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui)
@ -33,6 +49,7 @@ func (s *stepConfigureVNC) Run(ctx context.Context, state multistep.StateBag) mu
ui.Say(msg)
log.Print(msg)
var vncPassword string
var err error
s.l, err = net.ListenRangeConfig{
Addr: config.VNCBindAddress,
@ -41,7 +58,7 @@ func (s *stepConfigureVNC) Run(ctx context.Context, state multistep.StateBag) mu
Network: "tcp",
}.Listen(ctx)
if err != nil {
err := fmt.Errorf("Error finding port: %s", err)
err := fmt.Errorf("Error finding VNC port: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
@ -49,9 +66,15 @@ func (s *stepConfigureVNC) Run(ctx context.Context, state multistep.StateBag) mu
s.l.Listener.Close() // free port, but don't unlock lock file
vncPort := s.l.Port
if config.VNCUsePassword {
vncPassword = VNCPassword()
} else {
vncPassword = ""
}
log.Printf("Found available VNC port: %d on IP: %s", vncPort, config.VNCBindAddress)
state.Put("vnc_port", vncPort)
state.Put("vnc_ip", config.VNCBindAddress)
state.Put("vnc_password", vncPassword)
return multistep.ActionContinue
}

View File

@ -62,12 +62,10 @@ func (s *stepRun) Cleanup(state multistep.StateBag) {
func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error) {
config := state.Get("config").(*Config)
isoPath := state.Get("iso_path").(string)
vncIP := state.Get("vnc_ip").(string)
vncIP := config.VNCBindAddress
vncPort := state.Get("vnc_port").(int)
ui := state.Get("ui").(packer.Ui)
driver := state.Get("driver").(Driver)
vnc := fmt.Sprintf("%s:%d", vncIP, vncPort-5900)
vmName := config.VMName
imgPath := filepath.Join(config.OutputDir, vmName)
@ -75,6 +73,14 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
var deviceArgs []string
var driveArgs []string
var sshHostPort int
var vnc string
if !config.VNCUsePassword {
vnc = fmt.Sprintf("%s:%d", vncIP, vncPort-5900)
} else {
vnc = fmt.Sprintf("%s:%d,password", vncIP, vncPort-5900)
defaultArgs["-qmp"] = fmt.Sprintf("unix:%s,server,nowait", config.QMPSocketPath)
}
defaultArgs["-name"] = vmName
defaultArgs["-machine"] = fmt.Sprintf("type=%s", config.MachineType)
@ -137,17 +143,23 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
deviceArgs = append(deviceArgs, fmt.Sprintf("%s,netdev=user.0", config.NetDevice))
if config.Headless == true {
vncIpRaw, vncIpOk := state.GetOk("vnc_ip")
vncPortRaw, vncPortOk := state.GetOk("vnc_port")
vncPass := state.Get("vnc_password")
if vncIpOk && vncPortOk {
vncIp := vncIpRaw.(string)
if vncPortOk && vncPass != nil && len(vncPass.(string)) > 0 {
vncPort := vncPortRaw.(int)
ui.Message(fmt.Sprintf(
"The VM will be run headless, without a GUI. If you want to\n"+
"view the screen of the VM, connect via VNC to vnc://%s:%d\n"+
"with the password: %s", vncIP, vncPort, vncPass))
} else if vncPortOk {
vncPort := vncPortRaw.(int)
ui.Message(fmt.Sprintf(
"The VM will be run headless, without a GUI. If you want to\n"+
"view the screen of the VM, connect via VNC without a password to\n"+
"vnc://%s:%d", vncIp, vncPort))
"vnc://%s:%d", vncIP, vncPort))
} else {
ui.Message("The VM will be run headless, without a GUI, as configured.\n" +
"If the run isn't succeeding as you expect, please enable the GUI\n" +

View File

@ -41,7 +41,8 @@ func (s *stepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
httpPort := state.Get("http_port").(int)
ui := state.Get("ui").(packer.Ui)
vncPort := state.Get("vnc_port").(int)
vncIP := state.Get("vnc_ip").(string)
vncIP := config.VNCBindAddress
vncPassword := state.Get("vnc_password")
if config.VNCConfig.DisableVNC {
log.Println("Skipping boot command step...")
@ -76,7 +77,15 @@ func (s *stepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
}
defer nc.Close()
c, err := vnc.Client(nc, &vnc.ClientConfig{Exclusive: false})
var auth []vnc.ClientAuth
if vncPassword != nil && len(vncPassword.(string)) > 0 {
auth = []vnc.ClientAuth{&vnc.PasswordAuth{Password: vncPassword.(string)}}
} else {
auth = []vnc.ClientAuth{new(vnc.ClientAuthNone)}
}
c, err := vnc.Client(nc, &vnc.ClientConfig{Auth: auth, Exclusive: false})
if err != nil {
err := fmt.Errorf("Error handshaking with VNC: %s", err)
state.Put("error", err)

2
go.mod
View File

@ -26,6 +26,8 @@ require (
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/creack/goselect v0.1.0 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/digitalocean/go-libvirt v0.0.0-20190626172931-4d226dd6c437 // indirect
github.com/digitalocean/go-qemu v0.0.0-20181112162955-dd7bb9c771b8
github.com/digitalocean/godo v1.11.1
github.com/dnaeon/go-vcr v1.0.0 // indirect
github.com/docker/docker v0.0.0-20180422163414-57142e89befe // indirect

4
go.sum
View File

@ -91,6 +91,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/digitalocean/go-libvirt v0.0.0-20190626172931-4d226dd6c437 h1:phR13shVFOIpa1pnLBmewI9p16NEladLPvVylLPeexo=
github.com/digitalocean/go-libvirt v0.0.0-20190626172931-4d226dd6c437/go.mod h1:PRcPVAAma6zcLpFd4GZrjR/MRpood3TamjKI2m/z/Uw=
github.com/digitalocean/go-qemu v0.0.0-20181112162955-dd7bb9c771b8 h1:N7nH2py78LcMqYY3rZjjrsX6N7uCN7sjvaosgpXN9Ow=
github.com/digitalocean/go-qemu v0.0.0-20181112162955-dd7bb9c771b8/go.mod h1:/YnlngP1PARC0SKAZx6kaAEMOp8bNTQGqS+Ka3MctNI=
github.com/digitalocean/godo v1.11.1 h1:OsTh37YFKk+g6DnAOrkXJ9oDArTkRx5UTkBJ2EWAO38=
github.com/digitalocean/godo v1.11.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
github.com/dnaeon/go-vcr v1.0.0 h1:1QZ+ahihvRvppcJnFvuoHAdnZTf1PqKjO4Ftr1cfQTo=

62
vendor/github.com/digitalocean/go-libvirt/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,62 @@
language: go
os: linux
dist: bionic
sudo: require
cache:
directories:
- $HOME/.ccache
go:
- "1.12"
env:
global:
- CCACHE_TEMPDIR=/tmp/.ccache-temp
matrix:
- LIBVIRT=2.3.0 EXT=xz
- LIBVIRT=3.1.0 EXT=xz
- LIBVIRT=5.1.0 EXT=xz
before_install:
- go get golang.org/x/lint/golint
- go get golang.org/x/tools/cmd/goyacc
install:
# credit here goes to the go-libvirt authors,
# see: https://github.com/rgbkrk/libvirt-go/blob/master/.travis.yml
- sudo apt-get -qqy build-dep libvirt
- sudo apt-get -qqy install curl qemu-system-x86
- sudo mkdir -p /usr/src && sudo chown $(id -u) /usr/src
- curl -O -s https://libvirt.org/sources/libvirt-${LIBVIRT}.tar.${EXT}
- tar -C /usr/src -xf libvirt-${LIBVIRT}.tar.${EXT}
- pushd /usr/src/libvirt-${LIBVIRT}
- ccache --show-stats
- |
env PATH=/usr/lib/ccache:$PATH \
./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc \
--without-polkit \
--without-esx --without-vbox --without-xen --without-libxl --without-lxc \
--with-qemu
- make
- sudo make install
- ccache --show-stats
- popd
- sudo libvirtd -d -l -f libvirtd.conf
- sudo virtlogd -d || true
before_script:
- go get -d ./...
- sudo qemu-img create -f raw -o size=10M /var/lib/libvirt/images/test.raw
- sudo virsh define .travis/test-domain.xml
- sudo virsh start test
- sudo virsh pool-create .travis/test-pool.xml
- sudo virsh secret-define .travis/test-secret.xml
script:
- ./scripts/licensecheck.sh
- LIBVIRT_SOURCE=/usr/src/libvirt-${LIBVIRT} go generate ./...
- go build ./...
- golint -set_exit_status ./...
- go vet ./...
- go test -v -tags=integration ./...

22
vendor/github.com/digitalocean/go-libvirt/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,22 @@
Maintainer
----------
DigitalOcean, Inc
Original Authors
----------------
Ben LeMasurier <blemasurier@digitalocean.com>
Matt Layher <mlayher@digitalocean.com>
Contributors
------------
Justin Kim <justin@digitalocean.com>
Ricky Medina <rm@do.co>
Charlie Drage <charlie@charliedrage.com>
Michael Koppmann <me@mkoppmann.at>
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>
Sylvain Baubeau <sbaubeau@redhat.com>
David Schneider <dsbrng25b@gmail.com>

View File

@ -0,0 +1,30 @@
Contributing
============
The `go-libvirt` project makes use of the [GitHub Flow](https://guides.github.com/introduction/flow/)
for contributions.
If you'd like to contribute to the project, please
[open an issue](https://github.com/digitalocean/go-libvirt/issues/new) or find an
[existing issue](https://github.com/digitalocean/go-libvirt/issues) that you'd like
to take on. This ensures that efforts are not duplicated, and that a new feature
aligns with the focus of the rest of the repository.
Once your suggestion has been submitted and discussed, please be sure that your
code meets the following criteria:
- code is completely `gofmt`'d
- new features or codepaths have appropriate test coverage
- `go test ./...` passes
- `go vet ./...` passes
- `golint ./...` returns no warnings, including documentation comment warnings
In addition, if this is your first time contributing to the `go-libvirt` project,
add your name and email address to the
[AUTHORS](https://github.com/digitalocean/go-libvirt/blob/master/AUTHORS) file
under the "Contributors" section using the format:
`First Last <email@example.com>`.
Finally, submit a pull request for review!
Questions? Feel free to join us in [`#go-qemu` on freenode](https://webchat.freenode.net/)
if you'd like to discuss the project.

195
vendor/github.com/digitalocean/go-libvirt/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,195 @@
Apache License
==============
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
### Terms and Conditions for use, reproduction, and distribution
#### 1. Definitions
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
#### 2. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
#### 3. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
#### 4. Redistribution
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
#### 5. Submission of Contributions
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
#### 6. Trademarks
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
#### 7. Disclaimer of Warranty
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
#### 8. Limitation of Liability
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
#### 9. Accepting Warranty or Additional Liability
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
_END OF TERMS AND CONDITIONS_
### APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets `[]` replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same “printed page” as the copyright notice for easier identification within
third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

155
vendor/github.com/digitalocean/go-libvirt/README.md generated vendored Normal file
View File

@ -0,0 +1,155 @@
libvirt [![GoDoc](http://godoc.org/github.com/digitalocean/go-libvirt?status.svg)](http://godoc.org/github.com/digitalocean/go-libvirt) [![Build Status](https://travis-ci.org/digitalocean/go-libvirt.svg?branch=master)](https://travis-ci.org/digitalocean/go-libvirt) [![Report Card](https://goreportcard.com/badge/github.com/digitalocean/go-libvirt)](https://goreportcard.com/report/github.com/digitalocean/go-libvirt)
====
Package `go-libvirt` provides a pure Go interface for interacting with libvirt.
Rather than using libvirt's C bindings, this package makes use of
libvirt's RPC interface, as documented [here](https://libvirt.org/internals/rpc.html).
Connections to the libvirt server may be local, or remote. RPC packets are encoded
using the XDR standard as defined by [RFC 4506](https://tools.ietf.org/html/rfc4506.html).
libvirt's RPC interface is quite extensive, and changes from one version to the next, so
this project uses a code generator to build the go bindings. The code generator should
be run whenever you want to build go-libvirt for a new version of libvirt. To do this,
you'll need to set an environment variable `LIBVIRT_SOURCE` to the directory containing
the untarred libvirt sources, and then run `go generate ./...` from the go-libvirt directory.
The code generator consumes [src/remote/remote_protocol.x](https://github.com/libvirt/libvirt/blob/master/src/remote/remote_protocol.x)
and produces go bindings for all the remote procedures defined there.
[Pull requests are welcome](https://github.com/digitalocean/go-libvirt/blob/master/CONTRIBUTING.md)!
How to Use This Library
-----------------------
Once you've vendored go-libvirt into your project, you'll probably want to call
some libvirt functions. There's some example code below showing how to connect
to libvirt and make one such call, but once you get past the introduction you'll
next want to call some other libvirt functions. How do you find them?
Start with the [libvirt API reference](https://libvirt.org/html/index.html).
Let's say you want to gracefully shutdown a VM, and after reading through the
libvirt docs you determine that virDomainShutdown() is the function you want to
call to do that. Where's that function in go-libvirt? We transform the names
slightly when building the go bindings. There's no need for a global prefix like
"vir" in Go, since all our functions are inside the package namespace, so we
drop it. That means the Go function for `virDomainShutdown()` is just `DomainShutdown()`,
and sure enough, you can find the Go function `DomainShutdown()` in libvirt.gen.go,
with parameters and return values equivalent to those documented in the API
reference.
Suppose you then decide you need more control over your shutdown, so you switch
over to `virDomainShutdownFlags()`. As its name suggests, this function takes a
flag parameter which has possible values specified in an enum called
`virDomainShutdownFlagValues`. Flag types like this are a little tricky for the
code generator, because the C functions just take an integer type - only the
libvirt documentation actually ties the flags to the enum types. In most cases
though we're able to generate a wrapper function with a distinct flag type,
making it easier for Go tooling to suggest possible flag values while you're
working. Checking the documentation for this function:
`godoc github.com/digitalocean/go-libvirt DomainShutdownFlags`
returns this:
`func (l *Libvirt) DomainShutdownFlags(Dom Domain, Flags DomainShutdownFlagValues) (err error)`
If you want to see the possible flag values, `godoc` can help again:
```
$ godoc github.com/digitalocean/go-libvirt DomainShutdownFlagValues
type DomainShutdownFlagValues int32
DomainShutdownFlagValues as declared in libvirt/libvirt-domain.h:1121
const (
DomainShutdownDefault DomainShutdownFlagValues = iota
DomainShutdownAcpiPowerBtn DomainShutdownFlagValues = 1
DomainShutdownGuestAgent DomainShutdownFlagValues = 2
DomainShutdownInitctl DomainShutdownFlagValues = 4
DomainShutdownSignal DomainShutdownFlagValues = 8
DomainShutdownParavirt DomainShutdownFlagValues = 16
)
DomainShutdownFlagValues enumeration from libvirt/libvirt-domain.h:1121
```
One other suggestion: most of the code in go-libvirt is now generated, but a few
hand-written routines still exist in libvirt.go, and wrap calls to the generated
code with slightly different parameters or return values. We suggest avoiding
these hand-written routines and calling the generated routines in libvirt.gen.go
instead. Over time these handwritten routines will be removed from go-libvirt.
Warning
-------
The libvirt project strongly recommends *against* talking to the RPC interface
directly. They consider it to be a private implementation detail with the
possibility of being entirely rearchitected in the future.
While these package are reasonably well-tested and have seen some use inside of
DigitalOcean, there may be subtle bugs which could cause the packages to act
in unexpected ways. Use at your own risk!
In addition, the API is not considered stable at this time. If you would like
to include package `libvirt` in a project, we highly recommend vendoring it into
your project.
Example
-------
```go
package main
import (
"fmt"
"log"
"net"
"time"
"github.com/digitalocean/go-libvirt"
)
func main() {
// This dials libvirt on the local machine, but you can substitute the first
// two parameters with "tcp", "<ip address>:<port>" to connect to libvirt on
// a remote machine.
c, err := net.DialTimeout("unix", "/var/run/libvirt/libvirt-sock", 2*time.Second)
if err != nil {
log.Fatalf("failed to dial libvirt: %v", err)
}
l := libvirt.New(c)
if err := l.Connect(); err != nil {
log.Fatalf("failed to connect: %v", err)
}
v, err := l.Version()
if err != nil {
log.Fatalf("failed to retrieve libvirt version: %v", err)
}
fmt.Println("Version:", v)
domains, err := l.Domains()
if err != nil {
log.Fatalf("failed to retrieve domains: %v", err)
}
fmt.Println("ID\tName\t\tUUID")
fmt.Printf("--------------------------------------------------------\n")
for _, d := range domains {
fmt.Printf("%d\t%s\t%x\n", d.ID, d.Name, d.UUID)
}
if err := l.Disconnect(); err != nil {
log.Fatalf("failed to disconnect: %v", err)
}
}
```
```
Version: 1.3.4
ID Name UUID
--------------------------------------------------------
1 Test-1 dc329f87d4de47198cfd2e21c6105b01
2 Test-2 dc229f87d4de47198cfd2e21c6105b01
```

2242
vendor/github.com/digitalocean/go-libvirt/const.gen.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

76
vendor/github.com/digitalocean/go-libvirt/doc.go generated vendored Normal file
View File

@ -0,0 +1,76 @@
// 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.
/*
Package libvirt provides a pure Go interface for Libvirt.
Rather than using Libvirt's C bindings, this package makes use of
Libvirt's RPC interface, as documented here: https://libvirt.org/internals/rpc.html.
Connections to the libvirt server may be local, or remote. RPC packets are encoded
using the XDR standard as defined by RFC 4506.
This should be considered a work in progress. Most functionaly provided by the C
bindings have not yet made their way into this library. Pull requests are welcome!
The definition of the RPC protocol is in the libvirt source tree under src/rpc/virnetprotocol.x.
Example usage:
package main
import (
"fmt"
"log"
"net"
"time"
"github.com/digitalocean/go-libvirt"
)
func main() {
//c, err := net.DialTimeout("tcp", "127.0.0.1:16509", 2*time.Second)
//c, err := net.DialTimeout("tcp", "192.168.1.12:16509", 2*time.Second)
c, err := net.DialTimeout("unix", "/var/run/libvirt/libvirt-sock", 2*time.Second)
if err != nil {
log.Fatalf("failed to dial libvirt: %v", err)
}
l := libvirt.New(c)
if err := l.Connect(); err != nil {
log.Fatalf("failed to connect: %v", err)
}
v, err := l.Version()
if err != nil {
log.Fatalf("failed to retrieve libvirt version: %v", err)
}
fmt.Println("Version:", v)
domains, err := l.Domains()
if err != nil {
log.Fatalf("failed to retrieve domains: %v", err)
}
fmt.Println("ID\tName\t\tUUID")
fmt.Printf("--------------------------------------------------------\n")
for _, d := range domains {
fmt.Printf("%d\t%s\t%x\n", d.ID, d.Name, d.UUID)
}
if err := l.Disconnect(); err != nil {
log.Fatal("failed to disconnect: %v", err)
}
}
*/
package libvirt

View File

@ -0,0 +1,992 @@
// Copyright 2018 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.
//
// Code generated by internal/lvgen/generate.go. DO NOT EDIT.
//
// To regenerate, run 'go generate' in internal/lvgen.
//
package constants
// qemu constants
const (
ProgramQEMU = 0x20008087
ProgramKeepAlive = 0x6b656570
)
// qemu procedure identifiers
const (
QEMUDomainMonitor = 1
QEMUConnectDomainMonitorEventRegister = 4
QEMUConnectDomainMonitorEventDeregister = 5
QEMUDomainMonitorEvent = 6
)
const (
// PacketLengthSize is the packet length, in bytes.
PacketLengthSize = 4
// HeaderSize is the packet header size, in bytes.
HeaderSize = 24
// UUIDSize is the length of a UUID, in bytes.
UUIDSize = 16
)
// These are libvirt procedure numbers which correspond to each respective
// API call between remote_internal driver and libvirtd. Each procedure is
// identified by a unique number which *may change in any future libvirt
// update*.
//
// Examples:
// REMOTE_PROC_CONNECT_OPEN = 1
// REMOTE_PROC_DOMAIN_DEFINE_XML = 11
// REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207,
const (
// From enums:
// AuthNone is libvirt's REMOTE_AUTH_NONE
AuthNone = 0
// AuthSasl is libvirt's REMOTE_AUTH_SASL
AuthSasl = 1
// AuthPolkit is libvirt's REMOTE_AUTH_POLKIT
AuthPolkit = 2
// ProcConnectOpen is libvirt's REMOTE_PROC_CONNECT_OPEN
ProcConnectOpen = 1
// ProcConnectClose is libvirt's REMOTE_PROC_CONNECT_CLOSE
ProcConnectClose = 2
// ProcConnectGetType is libvirt's REMOTE_PROC_CONNECT_GET_TYPE
ProcConnectGetType = 3
// ProcConnectGetVersion is libvirt's REMOTE_PROC_CONNECT_GET_VERSION
ProcConnectGetVersion = 4
// ProcConnectGetMaxVcpus is libvirt's REMOTE_PROC_CONNECT_GET_MAX_VCPUS
ProcConnectGetMaxVcpus = 5
// ProcNodeGetInfo is libvirt's REMOTE_PROC_NODE_GET_INFO
ProcNodeGetInfo = 6
// ProcConnectGetCapabilities is libvirt's REMOTE_PROC_CONNECT_GET_CAPABILITIES
ProcConnectGetCapabilities = 7
// ProcDomainAttachDevice is libvirt's REMOTE_PROC_DOMAIN_ATTACH_DEVICE
ProcDomainAttachDevice = 8
// ProcDomainCreate is libvirt's REMOTE_PROC_DOMAIN_CREATE
ProcDomainCreate = 9
// ProcDomainCreateXML is libvirt's REMOTE_PROC_DOMAIN_CREATE_XML
ProcDomainCreateXML = 10
// ProcDomainDefineXML is libvirt's REMOTE_PROC_DOMAIN_DEFINE_XML
ProcDomainDefineXML = 11
// ProcDomainDestroy is libvirt's REMOTE_PROC_DOMAIN_DESTROY
ProcDomainDestroy = 12
// ProcDomainDetachDevice is libvirt's REMOTE_PROC_DOMAIN_DETACH_DEVICE
ProcDomainDetachDevice = 13
// ProcDomainGetXMLDesc is libvirt's REMOTE_PROC_DOMAIN_GET_XML_DESC
ProcDomainGetXMLDesc = 14
// ProcDomainGetAutostart is libvirt's REMOTE_PROC_DOMAIN_GET_AUTOSTART
ProcDomainGetAutostart = 15
// ProcDomainGetInfo is libvirt's REMOTE_PROC_DOMAIN_GET_INFO
ProcDomainGetInfo = 16
// ProcDomainGetMaxMemory is libvirt's REMOTE_PROC_DOMAIN_GET_MAX_MEMORY
ProcDomainGetMaxMemory = 17
// ProcDomainGetMaxVcpus is libvirt's REMOTE_PROC_DOMAIN_GET_MAX_VCPUS
ProcDomainGetMaxVcpus = 18
// ProcDomainGetOsType is libvirt's REMOTE_PROC_DOMAIN_GET_OS_TYPE
ProcDomainGetOsType = 19
// ProcDomainGetVcpus is libvirt's REMOTE_PROC_DOMAIN_GET_VCPUS
ProcDomainGetVcpus = 20
// ProcConnectListDefinedDomains is libvirt's REMOTE_PROC_CONNECT_LIST_DEFINED_DOMAINS
ProcConnectListDefinedDomains = 21
// ProcDomainLookupByID is libvirt's REMOTE_PROC_DOMAIN_LOOKUP_BY_ID
ProcDomainLookupByID = 22
// ProcDomainLookupByName is libvirt's REMOTE_PROC_DOMAIN_LOOKUP_BY_NAME
ProcDomainLookupByName = 23
// ProcDomainLookupByUUID is libvirt's REMOTE_PROC_DOMAIN_LOOKUP_BY_UUID
ProcDomainLookupByUUID = 24
// ProcConnectNumOfDefinedDomains is libvirt's REMOTE_PROC_CONNECT_NUM_OF_DEFINED_DOMAINS
ProcConnectNumOfDefinedDomains = 25
// ProcDomainPinVcpu is libvirt's REMOTE_PROC_DOMAIN_PIN_VCPU
ProcDomainPinVcpu = 26
// ProcDomainReboot is libvirt's REMOTE_PROC_DOMAIN_REBOOT
ProcDomainReboot = 27
// ProcDomainResume is libvirt's REMOTE_PROC_DOMAIN_RESUME
ProcDomainResume = 28
// ProcDomainSetAutostart is libvirt's REMOTE_PROC_DOMAIN_SET_AUTOSTART
ProcDomainSetAutostart = 29
// ProcDomainSetMaxMemory is libvirt's REMOTE_PROC_DOMAIN_SET_MAX_MEMORY
ProcDomainSetMaxMemory = 30
// ProcDomainSetMemory is libvirt's REMOTE_PROC_DOMAIN_SET_MEMORY
ProcDomainSetMemory = 31
// ProcDomainSetVcpus is libvirt's REMOTE_PROC_DOMAIN_SET_VCPUS
ProcDomainSetVcpus = 32
// ProcDomainShutdown is libvirt's REMOTE_PROC_DOMAIN_SHUTDOWN
ProcDomainShutdown = 33
// ProcDomainSuspend is libvirt's REMOTE_PROC_DOMAIN_SUSPEND
ProcDomainSuspend = 34
// ProcDomainUndefine is libvirt's REMOTE_PROC_DOMAIN_UNDEFINE
ProcDomainUndefine = 35
// ProcConnectListDefinedNetworks is libvirt's REMOTE_PROC_CONNECT_LIST_DEFINED_NETWORKS
ProcConnectListDefinedNetworks = 36
// ProcConnectListDomains is libvirt's REMOTE_PROC_CONNECT_LIST_DOMAINS
ProcConnectListDomains = 37
// ProcConnectListNetworks is libvirt's REMOTE_PROC_CONNECT_LIST_NETWORKS
ProcConnectListNetworks = 38
// ProcNetworkCreate is libvirt's REMOTE_PROC_NETWORK_CREATE
ProcNetworkCreate = 39
// ProcNetworkCreateXML is libvirt's REMOTE_PROC_NETWORK_CREATE_XML
ProcNetworkCreateXML = 40
// ProcNetworkDefineXML is libvirt's REMOTE_PROC_NETWORK_DEFINE_XML
ProcNetworkDefineXML = 41
// ProcNetworkDestroy is libvirt's REMOTE_PROC_NETWORK_DESTROY
ProcNetworkDestroy = 42
// ProcNetworkGetXMLDesc is libvirt's REMOTE_PROC_NETWORK_GET_XML_DESC
ProcNetworkGetXMLDesc = 43
// ProcNetworkGetAutostart is libvirt's REMOTE_PROC_NETWORK_GET_AUTOSTART
ProcNetworkGetAutostart = 44
// ProcNetworkGetBridgeName is libvirt's REMOTE_PROC_NETWORK_GET_BRIDGE_NAME
ProcNetworkGetBridgeName = 45
// ProcNetworkLookupByName is libvirt's REMOTE_PROC_NETWORK_LOOKUP_BY_NAME
ProcNetworkLookupByName = 46
// ProcNetworkLookupByUUID is libvirt's REMOTE_PROC_NETWORK_LOOKUP_BY_UUID
ProcNetworkLookupByUUID = 47
// ProcNetworkSetAutostart is libvirt's REMOTE_PROC_NETWORK_SET_AUTOSTART
ProcNetworkSetAutostart = 48
// ProcNetworkUndefine is libvirt's REMOTE_PROC_NETWORK_UNDEFINE
ProcNetworkUndefine = 49
// ProcConnectNumOfDefinedNetworks is libvirt's REMOTE_PROC_CONNECT_NUM_OF_DEFINED_NETWORKS
ProcConnectNumOfDefinedNetworks = 50
// ProcConnectNumOfDomains is libvirt's REMOTE_PROC_CONNECT_NUM_OF_DOMAINS
ProcConnectNumOfDomains = 51
// ProcConnectNumOfNetworks is libvirt's REMOTE_PROC_CONNECT_NUM_OF_NETWORKS
ProcConnectNumOfNetworks = 52
// ProcDomainCoreDump is libvirt's REMOTE_PROC_DOMAIN_CORE_DUMP
ProcDomainCoreDump = 53
// ProcDomainRestore is libvirt's REMOTE_PROC_DOMAIN_RESTORE
ProcDomainRestore = 54
// ProcDomainSave is libvirt's REMOTE_PROC_DOMAIN_SAVE
ProcDomainSave = 55
// ProcDomainGetSchedulerType is libvirt's REMOTE_PROC_DOMAIN_GET_SCHEDULER_TYPE
ProcDomainGetSchedulerType = 56
// ProcDomainGetSchedulerParameters is libvirt's REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS
ProcDomainGetSchedulerParameters = 57
// ProcDomainSetSchedulerParameters is libvirt's REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS
ProcDomainSetSchedulerParameters = 58
// ProcConnectGetHostname is libvirt's REMOTE_PROC_CONNECT_GET_HOSTNAME
ProcConnectGetHostname = 59
// ProcConnectSupportsFeature is libvirt's REMOTE_PROC_CONNECT_SUPPORTS_FEATURE
ProcConnectSupportsFeature = 60
// ProcDomainMigratePrepare is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_PREPARE
ProcDomainMigratePrepare = 61
// ProcDomainMigratePerform is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_PERFORM
ProcDomainMigratePerform = 62
// ProcDomainMigrateFinish is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_FINISH
ProcDomainMigrateFinish = 63
// ProcDomainBlockStats is libvirt's REMOTE_PROC_DOMAIN_BLOCK_STATS
ProcDomainBlockStats = 64
// ProcDomainInterfaceStats is libvirt's REMOTE_PROC_DOMAIN_INTERFACE_STATS
ProcDomainInterfaceStats = 65
// ProcAuthList is libvirt's REMOTE_PROC_AUTH_LIST
ProcAuthList = 66
// ProcAuthSaslInit is libvirt's REMOTE_PROC_AUTH_SASL_INIT
ProcAuthSaslInit = 67
// ProcAuthSaslStart is libvirt's REMOTE_PROC_AUTH_SASL_START
ProcAuthSaslStart = 68
// ProcAuthSaslStep is libvirt's REMOTE_PROC_AUTH_SASL_STEP
ProcAuthSaslStep = 69
// ProcAuthPolkit is libvirt's REMOTE_PROC_AUTH_POLKIT
ProcAuthPolkit = 70
// ProcConnectNumOfStoragePools is libvirt's REMOTE_PROC_CONNECT_NUM_OF_STORAGE_POOLS
ProcConnectNumOfStoragePools = 71
// ProcConnectListStoragePools is libvirt's REMOTE_PROC_CONNECT_LIST_STORAGE_POOLS
ProcConnectListStoragePools = 72
// ProcConnectNumOfDefinedStoragePools is libvirt's REMOTE_PROC_CONNECT_NUM_OF_DEFINED_STORAGE_POOLS
ProcConnectNumOfDefinedStoragePools = 73
// ProcConnectListDefinedStoragePools is libvirt's REMOTE_PROC_CONNECT_LIST_DEFINED_STORAGE_POOLS
ProcConnectListDefinedStoragePools = 74
// ProcConnectFindStoragePoolSources is libvirt's REMOTE_PROC_CONNECT_FIND_STORAGE_POOL_SOURCES
ProcConnectFindStoragePoolSources = 75
// ProcStoragePoolCreateXML is libvirt's REMOTE_PROC_STORAGE_POOL_CREATE_XML
ProcStoragePoolCreateXML = 76
// ProcStoragePoolDefineXML is libvirt's REMOTE_PROC_STORAGE_POOL_DEFINE_XML
ProcStoragePoolDefineXML = 77
// ProcStoragePoolCreate is libvirt's REMOTE_PROC_STORAGE_POOL_CREATE
ProcStoragePoolCreate = 78
// ProcStoragePoolBuild is libvirt's REMOTE_PROC_STORAGE_POOL_BUILD
ProcStoragePoolBuild = 79
// ProcStoragePoolDestroy is libvirt's REMOTE_PROC_STORAGE_POOL_DESTROY
ProcStoragePoolDestroy = 80
// ProcStoragePoolDelete is libvirt's REMOTE_PROC_STORAGE_POOL_DELETE
ProcStoragePoolDelete = 81
// ProcStoragePoolUndefine is libvirt's REMOTE_PROC_STORAGE_POOL_UNDEFINE
ProcStoragePoolUndefine = 82
// ProcStoragePoolRefresh is libvirt's REMOTE_PROC_STORAGE_POOL_REFRESH
ProcStoragePoolRefresh = 83
// ProcStoragePoolLookupByName is libvirt's REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_NAME
ProcStoragePoolLookupByName = 84
// ProcStoragePoolLookupByUUID is libvirt's REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_UUID
ProcStoragePoolLookupByUUID = 85
// ProcStoragePoolLookupByVolume is libvirt's REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_VOLUME
ProcStoragePoolLookupByVolume = 86
// ProcStoragePoolGetInfo is libvirt's REMOTE_PROC_STORAGE_POOL_GET_INFO
ProcStoragePoolGetInfo = 87
// ProcStoragePoolGetXMLDesc is libvirt's REMOTE_PROC_STORAGE_POOL_GET_XML_DESC
ProcStoragePoolGetXMLDesc = 88
// ProcStoragePoolGetAutostart is libvirt's REMOTE_PROC_STORAGE_POOL_GET_AUTOSTART
ProcStoragePoolGetAutostart = 89
// ProcStoragePoolSetAutostart is libvirt's REMOTE_PROC_STORAGE_POOL_SET_AUTOSTART
ProcStoragePoolSetAutostart = 90
// ProcStoragePoolNumOfVolumes is libvirt's REMOTE_PROC_STORAGE_POOL_NUM_OF_VOLUMES
ProcStoragePoolNumOfVolumes = 91
// ProcStoragePoolListVolumes is libvirt's REMOTE_PROC_STORAGE_POOL_LIST_VOLUMES
ProcStoragePoolListVolumes = 92
// ProcStorageVolCreateXML is libvirt's REMOTE_PROC_STORAGE_VOL_CREATE_XML
ProcStorageVolCreateXML = 93
// ProcStorageVolDelete is libvirt's REMOTE_PROC_STORAGE_VOL_DELETE
ProcStorageVolDelete = 94
// ProcStorageVolLookupByName is libvirt's REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_NAME
ProcStorageVolLookupByName = 95
// ProcStorageVolLookupByKey is libvirt's REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_KEY
ProcStorageVolLookupByKey = 96
// ProcStorageVolLookupByPath is libvirt's REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_PATH
ProcStorageVolLookupByPath = 97
// ProcStorageVolGetInfo is libvirt's REMOTE_PROC_STORAGE_VOL_GET_INFO
ProcStorageVolGetInfo = 98
// ProcStorageVolGetXMLDesc is libvirt's REMOTE_PROC_STORAGE_VOL_GET_XML_DESC
ProcStorageVolGetXMLDesc = 99
// ProcStorageVolGetPath is libvirt's REMOTE_PROC_STORAGE_VOL_GET_PATH
ProcStorageVolGetPath = 100
// ProcNodeGetCellsFreeMemory is libvirt's REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY
ProcNodeGetCellsFreeMemory = 101
// ProcNodeGetFreeMemory is libvirt's REMOTE_PROC_NODE_GET_FREE_MEMORY
ProcNodeGetFreeMemory = 102
// ProcDomainBlockPeek is libvirt's REMOTE_PROC_DOMAIN_BLOCK_PEEK
ProcDomainBlockPeek = 103
// ProcDomainMemoryPeek is libvirt's REMOTE_PROC_DOMAIN_MEMORY_PEEK
ProcDomainMemoryPeek = 104
// ProcConnectDomainEventRegister is libvirt's REMOTE_PROC_CONNECT_DOMAIN_EVENT_REGISTER
ProcConnectDomainEventRegister = 105
// ProcConnectDomainEventDeregister is libvirt's REMOTE_PROC_CONNECT_DOMAIN_EVENT_DEREGISTER
ProcConnectDomainEventDeregister = 106
// ProcDomainEventLifecycle is libvirt's REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE
ProcDomainEventLifecycle = 107
// ProcDomainMigratePrepare2 is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_PREPARE2
ProcDomainMigratePrepare2 = 108
// ProcDomainMigrateFinish2 is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_FINISH2
ProcDomainMigrateFinish2 = 109
// ProcConnectGetUri is libvirt's REMOTE_PROC_CONNECT_GET_URI
ProcConnectGetUri = 110
// ProcNodeNumOfDevices is libvirt's REMOTE_PROC_NODE_NUM_OF_DEVICES
ProcNodeNumOfDevices = 111
// ProcNodeListDevices is libvirt's REMOTE_PROC_NODE_LIST_DEVICES
ProcNodeListDevices = 112
// ProcNodeDeviceLookupByName is libvirt's REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_NAME
ProcNodeDeviceLookupByName = 113
// ProcNodeDeviceGetXMLDesc is libvirt's REMOTE_PROC_NODE_DEVICE_GET_XML_DESC
ProcNodeDeviceGetXMLDesc = 114
// ProcNodeDeviceGetParent is libvirt's REMOTE_PROC_NODE_DEVICE_GET_PARENT
ProcNodeDeviceGetParent = 115
// ProcNodeDeviceNumOfCaps is libvirt's REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS
ProcNodeDeviceNumOfCaps = 116
// ProcNodeDeviceListCaps is libvirt's REMOTE_PROC_NODE_DEVICE_LIST_CAPS
ProcNodeDeviceListCaps = 117
// ProcNodeDeviceDettach is libvirt's REMOTE_PROC_NODE_DEVICE_DETTACH
ProcNodeDeviceDettach = 118
// ProcNodeDeviceReAttach is libvirt's REMOTE_PROC_NODE_DEVICE_RE_ATTACH
ProcNodeDeviceReAttach = 119
// ProcNodeDeviceReset is libvirt's REMOTE_PROC_NODE_DEVICE_RESET
ProcNodeDeviceReset = 120
// ProcDomainGetSecurityLabel is libvirt's REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL
ProcDomainGetSecurityLabel = 121
// ProcNodeGetSecurityModel is libvirt's REMOTE_PROC_NODE_GET_SECURITY_MODEL
ProcNodeGetSecurityModel = 122
// ProcNodeDeviceCreateXML is libvirt's REMOTE_PROC_NODE_DEVICE_CREATE_XML
ProcNodeDeviceCreateXML = 123
// ProcNodeDeviceDestroy is libvirt's REMOTE_PROC_NODE_DEVICE_DESTROY
ProcNodeDeviceDestroy = 124
// ProcStorageVolCreateXMLFrom is libvirt's REMOTE_PROC_STORAGE_VOL_CREATE_XML_FROM
ProcStorageVolCreateXMLFrom = 125
// ProcConnectNumOfInterfaces is libvirt's REMOTE_PROC_CONNECT_NUM_OF_INTERFACES
ProcConnectNumOfInterfaces = 126
// ProcConnectListInterfaces is libvirt's REMOTE_PROC_CONNECT_LIST_INTERFACES
ProcConnectListInterfaces = 127
// ProcInterfaceLookupByName is libvirt's REMOTE_PROC_INTERFACE_LOOKUP_BY_NAME
ProcInterfaceLookupByName = 128
// ProcInterfaceLookupByMacString is libvirt's REMOTE_PROC_INTERFACE_LOOKUP_BY_MAC_STRING
ProcInterfaceLookupByMacString = 129
// ProcInterfaceGetXMLDesc is libvirt's REMOTE_PROC_INTERFACE_GET_XML_DESC
ProcInterfaceGetXMLDesc = 130
// ProcInterfaceDefineXML is libvirt's REMOTE_PROC_INTERFACE_DEFINE_XML
ProcInterfaceDefineXML = 131
// ProcInterfaceUndefine is libvirt's REMOTE_PROC_INTERFACE_UNDEFINE
ProcInterfaceUndefine = 132
// ProcInterfaceCreate is libvirt's REMOTE_PROC_INTERFACE_CREATE
ProcInterfaceCreate = 133
// ProcInterfaceDestroy is libvirt's REMOTE_PROC_INTERFACE_DESTROY
ProcInterfaceDestroy = 134
// ProcConnectDomainXMLFromNative is libvirt's REMOTE_PROC_CONNECT_DOMAIN_XML_FROM_NATIVE
ProcConnectDomainXMLFromNative = 135
// ProcConnectDomainXMLToNative is libvirt's REMOTE_PROC_CONNECT_DOMAIN_XML_TO_NATIVE
ProcConnectDomainXMLToNative = 136
// ProcConnectNumOfDefinedInterfaces is libvirt's REMOTE_PROC_CONNECT_NUM_OF_DEFINED_INTERFACES
ProcConnectNumOfDefinedInterfaces = 137
// ProcConnectListDefinedInterfaces is libvirt's REMOTE_PROC_CONNECT_LIST_DEFINED_INTERFACES
ProcConnectListDefinedInterfaces = 138
// ProcConnectNumOfSecrets is libvirt's REMOTE_PROC_CONNECT_NUM_OF_SECRETS
ProcConnectNumOfSecrets = 139
// ProcConnectListSecrets is libvirt's REMOTE_PROC_CONNECT_LIST_SECRETS
ProcConnectListSecrets = 140
// ProcSecretLookupByUUID is libvirt's REMOTE_PROC_SECRET_LOOKUP_BY_UUID
ProcSecretLookupByUUID = 141
// ProcSecretDefineXML is libvirt's REMOTE_PROC_SECRET_DEFINE_XML
ProcSecretDefineXML = 142
// ProcSecretGetXMLDesc is libvirt's REMOTE_PROC_SECRET_GET_XML_DESC
ProcSecretGetXMLDesc = 143
// ProcSecretSetValue is libvirt's REMOTE_PROC_SECRET_SET_VALUE
ProcSecretSetValue = 144
// ProcSecretGetValue is libvirt's REMOTE_PROC_SECRET_GET_VALUE
ProcSecretGetValue = 145
// ProcSecretUndefine is libvirt's REMOTE_PROC_SECRET_UNDEFINE
ProcSecretUndefine = 146
// ProcSecretLookupByUsage is libvirt's REMOTE_PROC_SECRET_LOOKUP_BY_USAGE
ProcSecretLookupByUsage = 147
// ProcDomainMigratePrepareTunnel is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL
ProcDomainMigratePrepareTunnel = 148
// ProcConnectIsSecure is libvirt's REMOTE_PROC_CONNECT_IS_SECURE
ProcConnectIsSecure = 149
// ProcDomainIsActive is libvirt's REMOTE_PROC_DOMAIN_IS_ACTIVE
ProcDomainIsActive = 150
// ProcDomainIsPersistent is libvirt's REMOTE_PROC_DOMAIN_IS_PERSISTENT
ProcDomainIsPersistent = 151
// ProcNetworkIsActive is libvirt's REMOTE_PROC_NETWORK_IS_ACTIVE
ProcNetworkIsActive = 152
// ProcNetworkIsPersistent is libvirt's REMOTE_PROC_NETWORK_IS_PERSISTENT
ProcNetworkIsPersistent = 153
// ProcStoragePoolIsActive is libvirt's REMOTE_PROC_STORAGE_POOL_IS_ACTIVE
ProcStoragePoolIsActive = 154
// ProcStoragePoolIsPersistent is libvirt's REMOTE_PROC_STORAGE_POOL_IS_PERSISTENT
ProcStoragePoolIsPersistent = 155
// ProcInterfaceIsActive is libvirt's REMOTE_PROC_INTERFACE_IS_ACTIVE
ProcInterfaceIsActive = 156
// ProcConnectGetLibVersion is libvirt's REMOTE_PROC_CONNECT_GET_LIB_VERSION
ProcConnectGetLibVersion = 157
// ProcConnectCompareCPU is libvirt's REMOTE_PROC_CONNECT_COMPARE_CPU
ProcConnectCompareCPU = 158
// ProcDomainMemoryStats is libvirt's REMOTE_PROC_DOMAIN_MEMORY_STATS
ProcDomainMemoryStats = 159
// ProcDomainAttachDeviceFlags is libvirt's REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS
ProcDomainAttachDeviceFlags = 160
// ProcDomainDetachDeviceFlags is libvirt's REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS
ProcDomainDetachDeviceFlags = 161
// ProcConnectBaselineCPU is libvirt's REMOTE_PROC_CONNECT_BASELINE_CPU
ProcConnectBaselineCPU = 162
// ProcDomainGetJobInfo is libvirt's REMOTE_PROC_DOMAIN_GET_JOB_INFO
ProcDomainGetJobInfo = 163
// ProcDomainAbortJob is libvirt's REMOTE_PROC_DOMAIN_ABORT_JOB
ProcDomainAbortJob = 164
// ProcStorageVolWipe is libvirt's REMOTE_PROC_STORAGE_VOL_WIPE
ProcStorageVolWipe = 165
// ProcDomainMigrateSetMaxDowntime is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME
ProcDomainMigrateSetMaxDowntime = 166
// ProcConnectDomainEventRegisterAny is libvirt's REMOTE_PROC_CONNECT_DOMAIN_EVENT_REGISTER_ANY
ProcConnectDomainEventRegisterAny = 167
// ProcConnectDomainEventDeregisterAny is libvirt's REMOTE_PROC_CONNECT_DOMAIN_EVENT_DEREGISTER_ANY
ProcConnectDomainEventDeregisterAny = 168
// ProcDomainEventReboot is libvirt's REMOTE_PROC_DOMAIN_EVENT_REBOOT
ProcDomainEventReboot = 169
// ProcDomainEventRtcChange is libvirt's REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE
ProcDomainEventRtcChange = 170
// ProcDomainEventWatchdog is libvirt's REMOTE_PROC_DOMAIN_EVENT_WATCHDOG
ProcDomainEventWatchdog = 171
// ProcDomainEventIOError is libvirt's REMOTE_PROC_DOMAIN_EVENT_IO_ERROR
ProcDomainEventIOError = 172
// ProcDomainEventGraphics is libvirt's REMOTE_PROC_DOMAIN_EVENT_GRAPHICS
ProcDomainEventGraphics = 173
// ProcDomainUpdateDeviceFlags is libvirt's REMOTE_PROC_DOMAIN_UPDATE_DEVICE_FLAGS
ProcDomainUpdateDeviceFlags = 174
// ProcNwfilterLookupByName is libvirt's REMOTE_PROC_NWFILTER_LOOKUP_BY_NAME
ProcNwfilterLookupByName = 175
// ProcNwfilterLookupByUUID is libvirt's REMOTE_PROC_NWFILTER_LOOKUP_BY_UUID
ProcNwfilterLookupByUUID = 176
// ProcNwfilterGetXMLDesc is libvirt's REMOTE_PROC_NWFILTER_GET_XML_DESC
ProcNwfilterGetXMLDesc = 177
// ProcConnectNumOfNwfilters is libvirt's REMOTE_PROC_CONNECT_NUM_OF_NWFILTERS
ProcConnectNumOfNwfilters = 178
// ProcConnectListNwfilters is libvirt's REMOTE_PROC_CONNECT_LIST_NWFILTERS
ProcConnectListNwfilters = 179
// ProcNwfilterDefineXML is libvirt's REMOTE_PROC_NWFILTER_DEFINE_XML
ProcNwfilterDefineXML = 180
// ProcNwfilterUndefine is libvirt's REMOTE_PROC_NWFILTER_UNDEFINE
ProcNwfilterUndefine = 181
// ProcDomainManagedSave is libvirt's REMOTE_PROC_DOMAIN_MANAGED_SAVE
ProcDomainManagedSave = 182
// ProcDomainHasManagedSaveImage is libvirt's REMOTE_PROC_DOMAIN_HAS_MANAGED_SAVE_IMAGE
ProcDomainHasManagedSaveImage = 183
// ProcDomainManagedSaveRemove is libvirt's REMOTE_PROC_DOMAIN_MANAGED_SAVE_REMOVE
ProcDomainManagedSaveRemove = 184
// ProcDomainSnapshotCreateXML is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_CREATE_XML
ProcDomainSnapshotCreateXML = 185
// ProcDomainSnapshotGetXMLDesc is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_GET_XML_DESC
ProcDomainSnapshotGetXMLDesc = 186
// ProcDomainSnapshotNum is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_NUM
ProcDomainSnapshotNum = 187
// ProcDomainSnapshotListNames is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_NAMES
ProcDomainSnapshotListNames = 188
// ProcDomainSnapshotLookupByName is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_LOOKUP_BY_NAME
ProcDomainSnapshotLookupByName = 189
// ProcDomainHasCurrentSnapshot is libvirt's REMOTE_PROC_DOMAIN_HAS_CURRENT_SNAPSHOT
ProcDomainHasCurrentSnapshot = 190
// ProcDomainSnapshotCurrent is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_CURRENT
ProcDomainSnapshotCurrent = 191
// ProcDomainRevertToSnapshot is libvirt's REMOTE_PROC_DOMAIN_REVERT_TO_SNAPSHOT
ProcDomainRevertToSnapshot = 192
// ProcDomainSnapshotDelete is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE
ProcDomainSnapshotDelete = 193
// ProcDomainGetBlockInfo is libvirt's REMOTE_PROC_DOMAIN_GET_BLOCK_INFO
ProcDomainGetBlockInfo = 194
// ProcDomainEventIOErrorReason is libvirt's REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON
ProcDomainEventIOErrorReason = 195
// ProcDomainCreateWithFlags is libvirt's REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS
ProcDomainCreateWithFlags = 196
// ProcDomainSetMemoryParameters is libvirt's REMOTE_PROC_DOMAIN_SET_MEMORY_PARAMETERS
ProcDomainSetMemoryParameters = 197
// ProcDomainGetMemoryParameters is libvirt's REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS
ProcDomainGetMemoryParameters = 198
// ProcDomainSetVcpusFlags is libvirt's REMOTE_PROC_DOMAIN_SET_VCPUS_FLAGS
ProcDomainSetVcpusFlags = 199
// ProcDomainGetVcpusFlags is libvirt's REMOTE_PROC_DOMAIN_GET_VCPUS_FLAGS
ProcDomainGetVcpusFlags = 200
// ProcDomainOpenConsole is libvirt's REMOTE_PROC_DOMAIN_OPEN_CONSOLE
ProcDomainOpenConsole = 201
// ProcDomainIsUpdated is libvirt's REMOTE_PROC_DOMAIN_IS_UPDATED
ProcDomainIsUpdated = 202
// ProcConnectGetSysinfo is libvirt's REMOTE_PROC_CONNECT_GET_SYSINFO
ProcConnectGetSysinfo = 203
// ProcDomainSetMemoryFlags is libvirt's REMOTE_PROC_DOMAIN_SET_MEMORY_FLAGS
ProcDomainSetMemoryFlags = 204
// ProcDomainSetBlkioParameters is libvirt's REMOTE_PROC_DOMAIN_SET_BLKIO_PARAMETERS
ProcDomainSetBlkioParameters = 205
// ProcDomainGetBlkioParameters is libvirt's REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS
ProcDomainGetBlkioParameters = 206
// ProcDomainMigrateSetMaxSpeed is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED
ProcDomainMigrateSetMaxSpeed = 207
// ProcStorageVolUpload is libvirt's REMOTE_PROC_STORAGE_VOL_UPLOAD
ProcStorageVolUpload = 208
// ProcStorageVolDownload is libvirt's REMOTE_PROC_STORAGE_VOL_DOWNLOAD
ProcStorageVolDownload = 209
// ProcDomainInjectNmi is libvirt's REMOTE_PROC_DOMAIN_INJECT_NMI
ProcDomainInjectNmi = 210
// ProcDomainScreenshot is libvirt's REMOTE_PROC_DOMAIN_SCREENSHOT
ProcDomainScreenshot = 211
// ProcDomainGetState is libvirt's REMOTE_PROC_DOMAIN_GET_STATE
ProcDomainGetState = 212
// ProcDomainMigrateBegin3 is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_BEGIN3
ProcDomainMigrateBegin3 = 213
// ProcDomainMigratePrepare3 is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_PREPARE3
ProcDomainMigratePrepare3 = 214
// ProcDomainMigratePrepareTunnel3 is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3
ProcDomainMigratePrepareTunnel3 = 215
// ProcDomainMigratePerform3 is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3
ProcDomainMigratePerform3 = 216
// ProcDomainMigrateFinish3 is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_FINISH3
ProcDomainMigrateFinish3 = 217
// ProcDomainMigrateConfirm3 is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3
ProcDomainMigrateConfirm3 = 218
// ProcDomainSetSchedulerParametersFlags is libvirt's REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS_FLAGS
ProcDomainSetSchedulerParametersFlags = 219
// ProcInterfaceChangeBegin is libvirt's REMOTE_PROC_INTERFACE_CHANGE_BEGIN
ProcInterfaceChangeBegin = 220
// ProcInterfaceChangeCommit is libvirt's REMOTE_PROC_INTERFACE_CHANGE_COMMIT
ProcInterfaceChangeCommit = 221
// ProcInterfaceChangeRollback is libvirt's REMOTE_PROC_INTERFACE_CHANGE_ROLLBACK
ProcInterfaceChangeRollback = 222
// ProcDomainGetSchedulerParametersFlags is libvirt's REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS_FLAGS
ProcDomainGetSchedulerParametersFlags = 223
// ProcDomainEventControlError is libvirt's REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR
ProcDomainEventControlError = 224
// ProcDomainPinVcpuFlags is libvirt's REMOTE_PROC_DOMAIN_PIN_VCPU_FLAGS
ProcDomainPinVcpuFlags = 225
// ProcDomainSendKey is libvirt's REMOTE_PROC_DOMAIN_SEND_KEY
ProcDomainSendKey = 226
// ProcNodeGetCPUStats is libvirt's REMOTE_PROC_NODE_GET_CPU_STATS
ProcNodeGetCPUStats = 227
// ProcNodeGetMemoryStats is libvirt's REMOTE_PROC_NODE_GET_MEMORY_STATS
ProcNodeGetMemoryStats = 228
// ProcDomainGetControlInfo is libvirt's REMOTE_PROC_DOMAIN_GET_CONTROL_INFO
ProcDomainGetControlInfo = 229
// ProcDomainGetVcpuPinInfo is libvirt's REMOTE_PROC_DOMAIN_GET_VCPU_PIN_INFO
ProcDomainGetVcpuPinInfo = 230
// ProcDomainUndefineFlags is libvirt's REMOTE_PROC_DOMAIN_UNDEFINE_FLAGS
ProcDomainUndefineFlags = 231
// ProcDomainSaveFlags is libvirt's REMOTE_PROC_DOMAIN_SAVE_FLAGS
ProcDomainSaveFlags = 232
// ProcDomainRestoreFlags is libvirt's REMOTE_PROC_DOMAIN_RESTORE_FLAGS
ProcDomainRestoreFlags = 233
// ProcDomainDestroyFlags is libvirt's REMOTE_PROC_DOMAIN_DESTROY_FLAGS
ProcDomainDestroyFlags = 234
// ProcDomainSaveImageGetXMLDesc is libvirt's REMOTE_PROC_DOMAIN_SAVE_IMAGE_GET_XML_DESC
ProcDomainSaveImageGetXMLDesc = 235
// ProcDomainSaveImageDefineXML is libvirt's REMOTE_PROC_DOMAIN_SAVE_IMAGE_DEFINE_XML
ProcDomainSaveImageDefineXML = 236
// ProcDomainBlockJobAbort is libvirt's REMOTE_PROC_DOMAIN_BLOCK_JOB_ABORT
ProcDomainBlockJobAbort = 237
// ProcDomainGetBlockJobInfo is libvirt's REMOTE_PROC_DOMAIN_GET_BLOCK_JOB_INFO
ProcDomainGetBlockJobInfo = 238
// ProcDomainBlockJobSetSpeed is libvirt's REMOTE_PROC_DOMAIN_BLOCK_JOB_SET_SPEED
ProcDomainBlockJobSetSpeed = 239
// ProcDomainBlockPull is libvirt's REMOTE_PROC_DOMAIN_BLOCK_PULL
ProcDomainBlockPull = 240
// ProcDomainEventBlockJob is libvirt's REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB
ProcDomainEventBlockJob = 241
// ProcDomainMigrateGetMaxSpeed is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_GET_MAX_SPEED
ProcDomainMigrateGetMaxSpeed = 242
// ProcDomainBlockStatsFlags is libvirt's REMOTE_PROC_DOMAIN_BLOCK_STATS_FLAGS
ProcDomainBlockStatsFlags = 243
// ProcDomainSnapshotGetParent is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_GET_PARENT
ProcDomainSnapshotGetParent = 244
// ProcDomainReset is libvirt's REMOTE_PROC_DOMAIN_RESET
ProcDomainReset = 245
// ProcDomainSnapshotNumChildren is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_NUM_CHILDREN
ProcDomainSnapshotNumChildren = 246
// ProcDomainSnapshotListChildrenNames is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES
ProcDomainSnapshotListChildrenNames = 247
// ProcDomainEventDiskChange is libvirt's REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE
ProcDomainEventDiskChange = 248
// ProcDomainOpenGraphics is libvirt's REMOTE_PROC_DOMAIN_OPEN_GRAPHICS
ProcDomainOpenGraphics = 249
// ProcNodeSuspendForDuration is libvirt's REMOTE_PROC_NODE_SUSPEND_FOR_DURATION
ProcNodeSuspendForDuration = 250
// ProcDomainBlockResize is libvirt's REMOTE_PROC_DOMAIN_BLOCK_RESIZE
ProcDomainBlockResize = 251
// ProcDomainSetBlockIOTune is libvirt's REMOTE_PROC_DOMAIN_SET_BLOCK_IO_TUNE
ProcDomainSetBlockIOTune = 252
// ProcDomainGetBlockIOTune is libvirt's REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE
ProcDomainGetBlockIOTune = 253
// ProcDomainSetNumaParameters is libvirt's REMOTE_PROC_DOMAIN_SET_NUMA_PARAMETERS
ProcDomainSetNumaParameters = 254
// ProcDomainGetNumaParameters is libvirt's REMOTE_PROC_DOMAIN_GET_NUMA_PARAMETERS
ProcDomainGetNumaParameters = 255
// ProcDomainSetInterfaceParameters is libvirt's REMOTE_PROC_DOMAIN_SET_INTERFACE_PARAMETERS
ProcDomainSetInterfaceParameters = 256
// ProcDomainGetInterfaceParameters is libvirt's REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS
ProcDomainGetInterfaceParameters = 257
// ProcDomainShutdownFlags is libvirt's REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS
ProcDomainShutdownFlags = 258
// ProcStorageVolWipePattern is libvirt's REMOTE_PROC_STORAGE_VOL_WIPE_PATTERN
ProcStorageVolWipePattern = 259
// ProcStorageVolResize is libvirt's REMOTE_PROC_STORAGE_VOL_RESIZE
ProcStorageVolResize = 260
// ProcDomainPmSuspendForDuration is libvirt's REMOTE_PROC_DOMAIN_PM_SUSPEND_FOR_DURATION
ProcDomainPmSuspendForDuration = 261
// ProcDomainGetCPUStats is libvirt's REMOTE_PROC_DOMAIN_GET_CPU_STATS
ProcDomainGetCPUStats = 262
// ProcDomainGetDiskErrors is libvirt's REMOTE_PROC_DOMAIN_GET_DISK_ERRORS
ProcDomainGetDiskErrors = 263
// ProcDomainSetMetadata is libvirt's REMOTE_PROC_DOMAIN_SET_METADATA
ProcDomainSetMetadata = 264
// ProcDomainGetMetadata is libvirt's REMOTE_PROC_DOMAIN_GET_METADATA
ProcDomainGetMetadata = 265
// ProcDomainBlockRebase is libvirt's REMOTE_PROC_DOMAIN_BLOCK_REBASE
ProcDomainBlockRebase = 266
// ProcDomainPmWakeup is libvirt's REMOTE_PROC_DOMAIN_PM_WAKEUP
ProcDomainPmWakeup = 267
// ProcDomainEventTrayChange is libvirt's REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE
ProcDomainEventTrayChange = 268
// ProcDomainEventPmwakeup is libvirt's REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP
ProcDomainEventPmwakeup = 269
// ProcDomainEventPmsuspend is libvirt's REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND
ProcDomainEventPmsuspend = 270
// ProcDomainSnapshotIsCurrent is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_IS_CURRENT
ProcDomainSnapshotIsCurrent = 271
// ProcDomainSnapshotHasMetadata is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_HAS_METADATA
ProcDomainSnapshotHasMetadata = 272
// ProcConnectListAllDomains is libvirt's REMOTE_PROC_CONNECT_LIST_ALL_DOMAINS
ProcConnectListAllDomains = 273
// ProcDomainListAllSnapshots is libvirt's REMOTE_PROC_DOMAIN_LIST_ALL_SNAPSHOTS
ProcDomainListAllSnapshots = 274
// ProcDomainSnapshotListAllChildren is libvirt's REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN
ProcDomainSnapshotListAllChildren = 275
// ProcDomainEventBalloonChange is libvirt's REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE
ProcDomainEventBalloonChange = 276
// ProcDomainGetHostname is libvirt's REMOTE_PROC_DOMAIN_GET_HOSTNAME
ProcDomainGetHostname = 277
// ProcDomainGetSecurityLabelList is libvirt's REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_LIST
ProcDomainGetSecurityLabelList = 278
// ProcDomainPinEmulator is libvirt's REMOTE_PROC_DOMAIN_PIN_EMULATOR
ProcDomainPinEmulator = 279
// ProcDomainGetEmulatorPinInfo is libvirt's REMOTE_PROC_DOMAIN_GET_EMULATOR_PIN_INFO
ProcDomainGetEmulatorPinInfo = 280
// ProcConnectListAllStoragePools is libvirt's REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS
ProcConnectListAllStoragePools = 281
// ProcStoragePoolListAllVolumes is libvirt's REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES
ProcStoragePoolListAllVolumes = 282
// ProcConnectListAllNetworks is libvirt's REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS
ProcConnectListAllNetworks = 283
// ProcConnectListAllInterfaces is libvirt's REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES
ProcConnectListAllInterfaces = 284
// ProcConnectListAllNodeDevices is libvirt's REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES
ProcConnectListAllNodeDevices = 285
// ProcConnectListAllNwfilters is libvirt's REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS
ProcConnectListAllNwfilters = 286
// ProcConnectListAllSecrets is libvirt's REMOTE_PROC_CONNECT_LIST_ALL_SECRETS
ProcConnectListAllSecrets = 287
// ProcNodeSetMemoryParameters is libvirt's REMOTE_PROC_NODE_SET_MEMORY_PARAMETERS
ProcNodeSetMemoryParameters = 288
// ProcNodeGetMemoryParameters is libvirt's REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS
ProcNodeGetMemoryParameters = 289
// ProcDomainBlockCommit is libvirt's REMOTE_PROC_DOMAIN_BLOCK_COMMIT
ProcDomainBlockCommit = 290
// ProcNetworkUpdate is libvirt's REMOTE_PROC_NETWORK_UPDATE
ProcNetworkUpdate = 291
// ProcDomainEventPmsuspendDisk is libvirt's REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND_DISK
ProcDomainEventPmsuspendDisk = 292
// ProcNodeGetCPUMap is libvirt's REMOTE_PROC_NODE_GET_CPU_MAP
ProcNodeGetCPUMap = 293
// ProcDomainFstrim is libvirt's REMOTE_PROC_DOMAIN_FSTRIM
ProcDomainFstrim = 294
// ProcDomainSendProcessSignal is libvirt's REMOTE_PROC_DOMAIN_SEND_PROCESS_SIGNAL
ProcDomainSendProcessSignal = 295
// ProcDomainOpenChannel is libvirt's REMOTE_PROC_DOMAIN_OPEN_CHANNEL
ProcDomainOpenChannel = 296
// ProcNodeDeviceLookupScsiHostByWwn is libvirt's REMOTE_PROC_NODE_DEVICE_LOOKUP_SCSI_HOST_BY_WWN
ProcNodeDeviceLookupScsiHostByWwn = 297
// ProcDomainGetJobStats is libvirt's REMOTE_PROC_DOMAIN_GET_JOB_STATS
ProcDomainGetJobStats = 298
// ProcDomainMigrateGetCompressionCache is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_GET_COMPRESSION_CACHE
ProcDomainMigrateGetCompressionCache = 299
// ProcDomainMigrateSetCompressionCache is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_SET_COMPRESSION_CACHE
ProcDomainMigrateSetCompressionCache = 300
// ProcNodeDeviceDetachFlags is libvirt's REMOTE_PROC_NODE_DEVICE_DETACH_FLAGS
ProcNodeDeviceDetachFlags = 301
// ProcDomainMigrateBegin3Params is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_BEGIN3_PARAMS
ProcDomainMigrateBegin3Params = 302
// ProcDomainMigratePrepare3Params is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_PREPARE3_PARAMS
ProcDomainMigratePrepare3Params = 303
// ProcDomainMigratePrepareTunnel3Params is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3_PARAMS
ProcDomainMigratePrepareTunnel3Params = 304
// ProcDomainMigratePerform3Params is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3_PARAMS
ProcDomainMigratePerform3Params = 305
// ProcDomainMigrateFinish3Params is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_FINISH3_PARAMS
ProcDomainMigrateFinish3Params = 306
// ProcDomainMigrateConfirm3Params is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS
ProcDomainMigrateConfirm3Params = 307
// ProcDomainSetMemoryStatsPeriod is libvirt's REMOTE_PROC_DOMAIN_SET_MEMORY_STATS_PERIOD
ProcDomainSetMemoryStatsPeriod = 308
// ProcDomainCreateXMLWithFiles is libvirt's REMOTE_PROC_DOMAIN_CREATE_XML_WITH_FILES
ProcDomainCreateXMLWithFiles = 309
// ProcDomainCreateWithFiles is libvirt's REMOTE_PROC_DOMAIN_CREATE_WITH_FILES
ProcDomainCreateWithFiles = 310
// ProcDomainEventDeviceRemoved is libvirt's REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED
ProcDomainEventDeviceRemoved = 311
// ProcConnectGetCPUModelNames is libvirt's REMOTE_PROC_CONNECT_GET_CPU_MODEL_NAMES
ProcConnectGetCPUModelNames = 312
// ProcConnectNetworkEventRegisterAny is libvirt's REMOTE_PROC_CONNECT_NETWORK_EVENT_REGISTER_ANY
ProcConnectNetworkEventRegisterAny = 313
// ProcConnectNetworkEventDeregisterAny is libvirt's REMOTE_PROC_CONNECT_NETWORK_EVENT_DEREGISTER_ANY
ProcConnectNetworkEventDeregisterAny = 314
// ProcNetworkEventLifecycle is libvirt's REMOTE_PROC_NETWORK_EVENT_LIFECYCLE
ProcNetworkEventLifecycle = 315
// ProcConnectDomainEventCallbackRegisterAny is libvirt's REMOTE_PROC_CONNECT_DOMAIN_EVENT_CALLBACK_REGISTER_ANY
ProcConnectDomainEventCallbackRegisterAny = 316
// ProcConnectDomainEventCallbackDeregisterAny is libvirt's REMOTE_PROC_CONNECT_DOMAIN_EVENT_CALLBACK_DEREGISTER_ANY
ProcConnectDomainEventCallbackDeregisterAny = 317
// ProcDomainEventCallbackLifecycle is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_LIFECYCLE
ProcDomainEventCallbackLifecycle = 318
// ProcDomainEventCallbackReboot is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_REBOOT
ProcDomainEventCallbackReboot = 319
// ProcDomainEventCallbackRtcChange is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_RTC_CHANGE
ProcDomainEventCallbackRtcChange = 320
// ProcDomainEventCallbackWatchdog is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_WATCHDOG
ProcDomainEventCallbackWatchdog = 321
// ProcDomainEventCallbackIOError is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_IO_ERROR
ProcDomainEventCallbackIOError = 322
// ProcDomainEventCallbackGraphics is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_GRAPHICS
ProcDomainEventCallbackGraphics = 323
// ProcDomainEventCallbackIOErrorReason is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_IO_ERROR_REASON
ProcDomainEventCallbackIOErrorReason = 324
// ProcDomainEventCallbackControlError is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CONTROL_ERROR
ProcDomainEventCallbackControlError = 325
// ProcDomainEventCallbackBlockJob is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BLOCK_JOB
ProcDomainEventCallbackBlockJob = 326
// ProcDomainEventCallbackDiskChange is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DISK_CHANGE
ProcDomainEventCallbackDiskChange = 327
// ProcDomainEventCallbackTrayChange is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TRAY_CHANGE
ProcDomainEventCallbackTrayChange = 328
// ProcDomainEventCallbackPmwakeup is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMWAKEUP
ProcDomainEventCallbackPmwakeup = 329
// ProcDomainEventCallbackPmsuspend is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND
ProcDomainEventCallbackPmsuspend = 330
// ProcDomainEventCallbackBalloonChange is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BALLOON_CHANGE
ProcDomainEventCallbackBalloonChange = 331
// ProcDomainEventCallbackPmsuspendDisk is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND_DISK
ProcDomainEventCallbackPmsuspendDisk = 332
// ProcDomainEventCallbackDeviceRemoved is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED
ProcDomainEventCallbackDeviceRemoved = 333
// ProcDomainCoreDumpWithFormat is libvirt's REMOTE_PROC_DOMAIN_CORE_DUMP_WITH_FORMAT
ProcDomainCoreDumpWithFormat = 334
// ProcDomainFsfreeze is libvirt's REMOTE_PROC_DOMAIN_FSFREEZE
ProcDomainFsfreeze = 335
// ProcDomainFsthaw is libvirt's REMOTE_PROC_DOMAIN_FSTHAW
ProcDomainFsthaw = 336
// ProcDomainGetTime is libvirt's REMOTE_PROC_DOMAIN_GET_TIME
ProcDomainGetTime = 337
// ProcDomainSetTime is libvirt's REMOTE_PROC_DOMAIN_SET_TIME
ProcDomainSetTime = 338
// ProcDomainEventBlockJob2 is libvirt's REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_2
ProcDomainEventBlockJob2 = 339
// ProcNodeGetFreePages is libvirt's REMOTE_PROC_NODE_GET_FREE_PAGES
ProcNodeGetFreePages = 340
// ProcNetworkGetDhcpLeases is libvirt's REMOTE_PROC_NETWORK_GET_DHCP_LEASES
ProcNetworkGetDhcpLeases = 341
// ProcConnectGetDomainCapabilities is libvirt's REMOTE_PROC_CONNECT_GET_DOMAIN_CAPABILITIES
ProcConnectGetDomainCapabilities = 342
// ProcDomainOpenGraphicsFd is libvirt's REMOTE_PROC_DOMAIN_OPEN_GRAPHICS_FD
ProcDomainOpenGraphicsFd = 343
// ProcConnectGetAllDomainStats is libvirt's REMOTE_PROC_CONNECT_GET_ALL_DOMAIN_STATS
ProcConnectGetAllDomainStats = 344
// ProcDomainBlockCopy is libvirt's REMOTE_PROC_DOMAIN_BLOCK_COPY
ProcDomainBlockCopy = 345
// ProcDomainEventCallbackTunable is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TUNABLE
ProcDomainEventCallbackTunable = 346
// ProcNodeAllocPages is libvirt's REMOTE_PROC_NODE_ALLOC_PAGES
ProcNodeAllocPages = 347
// ProcDomainEventCallbackAgentLifecycle is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE
ProcDomainEventCallbackAgentLifecycle = 348
// ProcDomainGetFsinfo is libvirt's REMOTE_PROC_DOMAIN_GET_FSINFO
ProcDomainGetFsinfo = 349
// ProcDomainDefineXMLFlags is libvirt's REMOTE_PROC_DOMAIN_DEFINE_XML_FLAGS
ProcDomainDefineXMLFlags = 350
// ProcDomainGetIothreadInfo is libvirt's REMOTE_PROC_DOMAIN_GET_IOTHREAD_INFO
ProcDomainGetIothreadInfo = 351
// ProcDomainPinIothread is libvirt's REMOTE_PROC_DOMAIN_PIN_IOTHREAD
ProcDomainPinIothread = 352
// ProcDomainInterfaceAddresses is libvirt's REMOTE_PROC_DOMAIN_INTERFACE_ADDRESSES
ProcDomainInterfaceAddresses = 353
// ProcDomainEventCallbackDeviceAdded is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_ADDED
ProcDomainEventCallbackDeviceAdded = 354
// ProcDomainAddIothread is libvirt's REMOTE_PROC_DOMAIN_ADD_IOTHREAD
ProcDomainAddIothread = 355
// ProcDomainDelIothread is libvirt's REMOTE_PROC_DOMAIN_DEL_IOTHREAD
ProcDomainDelIothread = 356
// ProcDomainSetUserPassword is libvirt's REMOTE_PROC_DOMAIN_SET_USER_PASSWORD
ProcDomainSetUserPassword = 357
// ProcDomainRename is libvirt's REMOTE_PROC_DOMAIN_RENAME
ProcDomainRename = 358
// ProcDomainEventCallbackMigrationIteration is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_MIGRATION_ITERATION
ProcDomainEventCallbackMigrationIteration = 359
// ProcConnectRegisterCloseCallback is libvirt's REMOTE_PROC_CONNECT_REGISTER_CLOSE_CALLBACK
ProcConnectRegisterCloseCallback = 360
// ProcConnectUnregisterCloseCallback is libvirt's REMOTE_PROC_CONNECT_UNREGISTER_CLOSE_CALLBACK
ProcConnectUnregisterCloseCallback = 361
// ProcConnectEventConnectionClosed is libvirt's REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED
ProcConnectEventConnectionClosed = 362
// ProcDomainEventCallbackJobCompleted is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_JOB_COMPLETED
ProcDomainEventCallbackJobCompleted = 363
// ProcDomainMigrateStartPostCopy is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_START_POST_COPY
ProcDomainMigrateStartPostCopy = 364
// ProcDomainGetPerfEvents is libvirt's REMOTE_PROC_DOMAIN_GET_PERF_EVENTS
ProcDomainGetPerfEvents = 365
// ProcDomainSetPerfEvents is libvirt's REMOTE_PROC_DOMAIN_SET_PERF_EVENTS
ProcDomainSetPerfEvents = 366
// ProcDomainEventCallbackDeviceRemovalFailed is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED
ProcDomainEventCallbackDeviceRemovalFailed = 367
// ProcConnectStoragePoolEventRegisterAny is libvirt's REMOTE_PROC_CONNECT_STORAGE_POOL_EVENT_REGISTER_ANY
ProcConnectStoragePoolEventRegisterAny = 368
// ProcConnectStoragePoolEventDeregisterAny is libvirt's REMOTE_PROC_CONNECT_STORAGE_POOL_EVENT_DEREGISTER_ANY
ProcConnectStoragePoolEventDeregisterAny = 369
// ProcStoragePoolEventLifecycle is libvirt's REMOTE_PROC_STORAGE_POOL_EVENT_LIFECYCLE
ProcStoragePoolEventLifecycle = 370
// ProcDomainGetGuestVcpus is libvirt's REMOTE_PROC_DOMAIN_GET_GUEST_VCPUS
ProcDomainGetGuestVcpus = 371
// ProcDomainSetGuestVcpus is libvirt's REMOTE_PROC_DOMAIN_SET_GUEST_VCPUS
ProcDomainSetGuestVcpus = 372
// ProcStoragePoolEventRefresh is libvirt's REMOTE_PROC_STORAGE_POOL_EVENT_REFRESH
ProcStoragePoolEventRefresh = 373
// ProcConnectNodeDeviceEventRegisterAny is libvirt's REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_REGISTER_ANY
ProcConnectNodeDeviceEventRegisterAny = 374
// ProcConnectNodeDeviceEventDeregisterAny is libvirt's REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_DEREGISTER_ANY
ProcConnectNodeDeviceEventDeregisterAny = 375
// ProcNodeDeviceEventLifecycle is libvirt's REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE
ProcNodeDeviceEventLifecycle = 376
// ProcNodeDeviceEventUpdate is libvirt's REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE
ProcNodeDeviceEventUpdate = 377
// ProcStorageVolGetInfoFlags is libvirt's REMOTE_PROC_STORAGE_VOL_GET_INFO_FLAGS
ProcStorageVolGetInfoFlags = 378
// ProcDomainEventCallbackMetadataChange is libvirt's REMOTE_PROC_DOMAIN_EVENT_CALLBACK_METADATA_CHANGE
ProcDomainEventCallbackMetadataChange = 379
// ProcConnectSecretEventRegisterAny is libvirt's REMOTE_PROC_CONNECT_SECRET_EVENT_REGISTER_ANY
ProcConnectSecretEventRegisterAny = 380
// ProcConnectSecretEventDeregisterAny is libvirt's REMOTE_PROC_CONNECT_SECRET_EVENT_DEREGISTER_ANY
ProcConnectSecretEventDeregisterAny = 381
// ProcSecretEventLifecycle is libvirt's REMOTE_PROC_SECRET_EVENT_LIFECYCLE
ProcSecretEventLifecycle = 382
// ProcSecretEventValueChanged is libvirt's REMOTE_PROC_SECRET_EVENT_VALUE_CHANGED
ProcSecretEventValueChanged = 383
// ProcDomainSetVcpu is libvirt's REMOTE_PROC_DOMAIN_SET_VCPU
ProcDomainSetVcpu = 384
// ProcDomainEventBlockThreshold is libvirt's REMOTE_PROC_DOMAIN_EVENT_BLOCK_THRESHOLD
ProcDomainEventBlockThreshold = 385
// ProcDomainSetBlockThreshold is libvirt's REMOTE_PROC_DOMAIN_SET_BLOCK_THRESHOLD
ProcDomainSetBlockThreshold = 386
// ProcDomainMigrateGetMaxDowntime is libvirt's REMOTE_PROC_DOMAIN_MIGRATE_GET_MAX_DOWNTIME
ProcDomainMigrateGetMaxDowntime = 387
// ProcDomainManagedSaveGetXMLDesc is libvirt's REMOTE_PROC_DOMAIN_MANAGED_SAVE_GET_XML_DESC
ProcDomainManagedSaveGetXMLDesc = 388
// ProcDomainManagedSaveDefineXML is libvirt's REMOTE_PROC_DOMAIN_MANAGED_SAVE_DEFINE_XML
ProcDomainManagedSaveDefineXML = 389
// ProcDomainSetLifecycleAction is libvirt's REMOTE_PROC_DOMAIN_SET_LIFECYCLE_ACTION
ProcDomainSetLifecycleAction = 390
// ProcStoragePoolLookupByTargetPath is libvirt's REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH
ProcStoragePoolLookupByTargetPath = 391
// ProcDomainDetachDeviceAlias is libvirt's REMOTE_PROC_DOMAIN_DETACH_DEVICE_ALIAS
ProcDomainDetachDeviceAlias = 392
// ProcConnectCompareHypervisorCPU is libvirt's REMOTE_PROC_CONNECT_COMPARE_HYPERVISOR_CPU
ProcConnectCompareHypervisorCPU = 393
// ProcConnectBaselineHypervisorCPU is libvirt's REMOTE_PROC_CONNECT_BASELINE_HYPERVISOR_CPU
ProcConnectBaselineHypervisorCPU = 394
// ProcNodeGetSevInfo is libvirt's REMOTE_PROC_NODE_GET_SEV_INFO
ProcNodeGetSevInfo = 395
// ProcDomainGetLaunchSecurityInfo is libvirt's REMOTE_PROC_DOMAIN_GET_LAUNCH_SECURITY_INFO
ProcDomainGetLaunchSecurityInfo = 396
// ProcNwfilterBindingLookupByPortDev is libvirt's REMOTE_PROC_NWFILTER_BINDING_LOOKUP_BY_PORT_DEV
ProcNwfilterBindingLookupByPortDev = 397
// ProcNwfilterBindingGetXMLDesc is libvirt's REMOTE_PROC_NWFILTER_BINDING_GET_XML_DESC
ProcNwfilterBindingGetXMLDesc = 398
// ProcNwfilterBindingCreateXML is libvirt's REMOTE_PROC_NWFILTER_BINDING_CREATE_XML
ProcNwfilterBindingCreateXML = 399
// ProcNwfilterBindingDelete is libvirt's REMOTE_PROC_NWFILTER_BINDING_DELETE
ProcNwfilterBindingDelete = 400
// ProcConnectListAllNwfilterBindings is libvirt's REMOTE_PROC_CONNECT_LIST_ALL_NWFILTER_BINDINGS
ProcConnectListAllNwfilterBindings = 401
// ProcDomainSetIothreadParams is libvirt's REMOTE_PROC_DOMAIN_SET_IOTHREAD_PARAMS
ProcDomainSetIothreadParams = 402
// From consts:
// StringMax is libvirt's REMOTE_STRING_MAX
StringMax = 4194304
// DomainListMax is libvirt's REMOTE_DOMAIN_LIST_MAX
DomainListMax = 16384
// CpumapMax is libvirt's REMOTE_CPUMAP_MAX
CpumapMax = 2048
// VcpuinfoMax is libvirt's REMOTE_VCPUINFO_MAX
VcpuinfoMax = 16384
// CpumapsMax is libvirt's REMOTE_CPUMAPS_MAX
CpumapsMax = 8388608
// IothreadInfoMax is libvirt's REMOTE_IOTHREAD_INFO_MAX
IothreadInfoMax = 16384
// MigrateCookieMax is libvirt's REMOTE_MIGRATE_COOKIE_MAX
MigrateCookieMax = 4194304
// NetworkListMax is libvirt's REMOTE_NETWORK_LIST_MAX
NetworkListMax = 16384
// InterfaceListMax is libvirt's REMOTE_INTERFACE_LIST_MAX
InterfaceListMax = 16384
// StoragePoolListMax is libvirt's REMOTE_STORAGE_POOL_LIST_MAX
StoragePoolListMax = 16384
// StorageVolListMax is libvirt's REMOTE_STORAGE_VOL_LIST_MAX
StorageVolListMax = 16384
// NodeDeviceListMax is libvirt's REMOTE_NODE_DEVICE_LIST_MAX
NodeDeviceListMax = 65536
// NodeDeviceCapsListMax is libvirt's REMOTE_NODE_DEVICE_CAPS_LIST_MAX
NodeDeviceCapsListMax = 65536
// NwfilterListMax is libvirt's REMOTE_NWFILTER_LIST_MAX
NwfilterListMax = 16384
// NwfilterBindingListMax is libvirt's REMOTE_NWFILTER_BINDING_LIST_MAX
NwfilterBindingListMax = 16384
// DomainSchedulerParametersMax is libvirt's REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX
DomainSchedulerParametersMax = 16
// DomainBlkioParametersMax is libvirt's REMOTE_DOMAIN_BLKIO_PARAMETERS_MAX
DomainBlkioParametersMax = 16
// DomainMemoryParametersMax is libvirt's REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX
DomainMemoryParametersMax = 16
// DomainBlockIOTuneParametersMax is libvirt's REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX
DomainBlockIOTuneParametersMax = 32
// DomainNumaParametersMax is libvirt's REMOTE_DOMAIN_NUMA_PARAMETERS_MAX
DomainNumaParametersMax = 16
// DomainPerfEventsMax is libvirt's REMOTE_DOMAIN_PERF_EVENTS_MAX
DomainPerfEventsMax = 64
// DomainBlockCopyParametersMax is libvirt's REMOTE_DOMAIN_BLOCK_COPY_PARAMETERS_MAX
DomainBlockCopyParametersMax = 16
// NodeCPUStatsMax is libvirt's REMOTE_NODE_CPU_STATS_MAX
NodeCPUStatsMax = 16
// NodeMemoryStatsMax is libvirt's REMOTE_NODE_MEMORY_STATS_MAX
NodeMemoryStatsMax = 16
// DomainBlockStatsParametersMax is libvirt's REMOTE_DOMAIN_BLOCK_STATS_PARAMETERS_MAX
DomainBlockStatsParametersMax = 16
// NodeMaxCells is libvirt's REMOTE_NODE_MAX_CELLS
NodeMaxCells = 1024
// AuthSaslDataMax is libvirt's REMOTE_AUTH_SASL_DATA_MAX
AuthSaslDataMax = 65536
// AuthTypeListMax is libvirt's REMOTE_AUTH_TYPE_LIST_MAX
AuthTypeListMax = 20
// DomainMemoryStatsMax is libvirt's REMOTE_DOMAIN_MEMORY_STATS_MAX
DomainMemoryStatsMax = 1024
// DomainSnapshotListMax is libvirt's REMOTE_DOMAIN_SNAPSHOT_LIST_MAX
DomainSnapshotListMax = 16384
// DomainBlockPeekBufferMax is libvirt's REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX
DomainBlockPeekBufferMax = 4194304
// DomainMemoryPeekBufferMax is libvirt's REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX
DomainMemoryPeekBufferMax = 4194304
// SecurityLabelListMax is libvirt's REMOTE_SECURITY_LABEL_LIST_MAX
SecurityLabelListMax = 64
// SecretValueMax is libvirt's REMOTE_SECRET_VALUE_MAX
SecretValueMax = 65536
// SecretListMax is libvirt's REMOTE_SECRET_LIST_MAX
SecretListMax = 16384
// CPUBaselineMax is libvirt's REMOTE_CPU_BASELINE_MAX
CPUBaselineMax = 256
// DomainSendKeyMax is libvirt's REMOTE_DOMAIN_SEND_KEY_MAX
DomainSendKeyMax = 16
// DomainInterfaceParametersMax is libvirt's REMOTE_DOMAIN_INTERFACE_PARAMETERS_MAX
DomainInterfaceParametersMax = 16
// DomainGetCPUStatsNcpusMax is libvirt's REMOTE_DOMAIN_GET_CPU_STATS_NCPUS_MAX
DomainGetCPUStatsNcpusMax = 128
// DomainGetCPUStatsMax is libvirt's REMOTE_DOMAIN_GET_CPU_STATS_MAX
DomainGetCPUStatsMax = 2048
// DomainDiskErrorsMax is libvirt's REMOTE_DOMAIN_DISK_ERRORS_MAX
DomainDiskErrorsMax = 256
// NodeMemoryParametersMax is libvirt's REMOTE_NODE_MEMORY_PARAMETERS_MAX
NodeMemoryParametersMax = 64
// DomainMigrateParamListMax is libvirt's REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX
DomainMigrateParamListMax = 64
// DomainJobStatsMax is libvirt's REMOTE_DOMAIN_JOB_STATS_MAX
DomainJobStatsMax = 64
// ConnectCPUModelsMax is libvirt's REMOTE_CONNECT_CPU_MODELS_MAX
ConnectCPUModelsMax = 8192
// DomainFsfreezeMountpointsMax is libvirt's REMOTE_DOMAIN_FSFREEZE_MOUNTPOINTS_MAX
DomainFsfreezeMountpointsMax = 256
// NetworkDhcpLeasesMax is libvirt's REMOTE_NETWORK_DHCP_LEASES_MAX
NetworkDhcpLeasesMax = 65536
// ConnectGetAllDomainStatsMax is libvirt's REMOTE_CONNECT_GET_ALL_DOMAIN_STATS_MAX
ConnectGetAllDomainStatsMax = 262144
// DomainEventTunableMax is libvirt's REMOTE_DOMAIN_EVENT_TUNABLE_MAX
DomainEventTunableMax = 2048
// DomainFsinfoMax is libvirt's REMOTE_DOMAIN_FSINFO_MAX
DomainFsinfoMax = 256
// DomainFsinfoDisksMax is libvirt's REMOTE_DOMAIN_FSINFO_DISKS_MAX
DomainFsinfoDisksMax = 256
// DomainInterfaceMax is libvirt's REMOTE_DOMAIN_INTERFACE_MAX
DomainInterfaceMax = 2048
// DomainIPAddrMax is libvirt's REMOTE_DOMAIN_IP_ADDR_MAX
DomainIPAddrMax = 2048
// DomainGuestVcpuParamsMax is libvirt's REMOTE_DOMAIN_GUEST_VCPU_PARAMS_MAX
DomainGuestVcpuParamsMax = 64
// DomainIothreadParamsMax is libvirt's REMOTE_DOMAIN_IOTHREAD_PARAMS_MAX
DomainIothreadParamsMax = 64
// NodeSevInfoMax is libvirt's REMOTE_NODE_SEV_INFO_MAX
NodeSevInfoMax = 64
// DomainLaunchSecurityInfoParamsMax is libvirt's REMOTE_DOMAIN_LAUNCH_SECURITY_INFO_PARAMS_MAX
DomainLaunchSecurityInfoParamsMax = 64
// DomainEventGraphicsIdentityMax is libvirt's REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX
DomainEventGraphicsIdentityMax = 20
// Program is libvirt's REMOTE_PROGRAM
Program = 0x20008086
// ProtocolVersion is libvirt's REMOTE_PROTOCOL_VERSION
ProtocolVersion = 1
)

View File

@ -0,0 +1,13 @@
Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -0,0 +1,896 @@
/*
* Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package xdr
import (
"fmt"
"io"
"math"
"reflect"
"time"
)
var (
errMaxSlice = "data exceeds max slice limit"
errIODecode = "%s while decoding %d bytes"
)
/*
Unmarshal parses XDR-encoded data into the value pointed to by v reading from
reader r and returning the total number of bytes read. An addressable pointer
must be provided since Unmarshal needs to both store the result of the decode as
well as obtain target type information. Unmarhsal traverses v recursively and
automatically indirects pointers through arbitrary depth, allocating them as
necessary, to decode the data into the underlying value pointed to.
Unmarshal uses reflection to determine the type of the concrete value contained
by v and performs a mapping of underlying XDR types to Go types as follows:
Go Type <- XDR Type
--------------------
int8, int16, int32, int <- XDR Integer
uint8, uint16, uint32, uint <- XDR Unsigned Integer
int64 <- XDR Hyper Integer
uint64 <- XDR Unsigned Hyper Integer
bool <- XDR Boolean
float32 <- XDR Floating-Point
float64 <- XDR Double-Precision Floating-Point
string <- XDR String
byte <- XDR Integer
[]byte <- XDR Variable-Length Opaque Data
[#]byte <- XDR Fixed-Length Opaque Data
[]<type> <- XDR Variable-Length Array
[#]<type> <- XDR Fixed-Length Array
struct <- XDR Structure
map <- XDR Variable-Length Array of two-element XDR Structures
time.Time <- XDR String encoded with RFC3339 nanosecond precision
Notes and Limitations:
* Automatic unmarshalling of variable and fixed-length arrays of uint8s
requires a special struct tag `xdropaque:"false"` since byte slices
and byte arrays are assumed to be opaque data and byte is a Go alias
for uint8 thus indistinguishable under reflection
* Cyclic data structures are not supported and will result in infinite
loops
If any issues are encountered during the unmarshalling process, an
UnmarshalError is returned with a human readable description as well as
an ErrorCode value for further inspection from sophisticated callers. Some
potential issues are unsupported Go types, attempting to decode a value which is
too large to fit into a specified Go type, and exceeding max slice limitations.
*/
func Unmarshal(r io.Reader, v interface{}) (int, error) {
d := Decoder{r: r}
return d.Decode(v)
}
// UnmarshalLimited is identical to Unmarshal but it sets maxReadSize in order
// to cap reads.
func UnmarshalLimited(r io.Reader, v interface{}, maxSize uint) (int, error) {
d := Decoder{r: r, maxReadSize: maxSize}
return d.Decode(v)
}
// TypeDecoder lets a caller provide a custom decode routine for a custom type.
type TypeDecoder interface {
Decode(*Decoder, reflect.Value) (int, error)
}
// A Decoder wraps an io.Reader that is expected to provide an XDR-encoded byte
// stream and provides several exposed methods to manually decode various XDR
// primitives without relying on reflection. The NewDecoder function can be
// used to get a new Decoder directly.
//
// Typically, Unmarshal should be used instead of manual decoding. A Decoder
// is exposed so it is possible to perform manual decoding should it be
// necessary in complex scenarios where automatic reflection-based decoding
// won't work.
type Decoder struct {
r io.Reader
// maxReadSize is the default maximum bytes an element can contain. 0
// is unlimited and provides backwards compatability. Setting it to a
// non-zero value caps reads.
maxReadSize uint
// customTypes is a map allowing the caller to provide decoder routines for
// custom types known only to itself.
customTypes map[string]TypeDecoder
}
// DecodeInt treats the next 4 bytes as an XDR encoded integer and returns the
// result as an int32 along with the number of bytes actually read.
//
// An UnmarshalError is returned if there are insufficient bytes remaining.
//
// Reference:
// RFC Section 4.1 - Integer
// 32-bit big-endian signed integer in range [-2147483648, 2147483647]
func (d *Decoder) DecodeInt() (int32, int, error) {
var buf [4]byte
n, err := io.ReadFull(d.r, buf[:])
if err != nil {
msg := fmt.Sprintf(errIODecode, err.Error(), 4)
err := unmarshalError("DecodeInt", ErrIO, msg, buf[:n], err)
return 0, n, err
}
rv := int32(buf[3]) | int32(buf[2])<<8 |
int32(buf[1])<<16 | int32(buf[0])<<24
return rv, n, nil
}
// DecodeUint treats the next 4 bytes as an XDR encoded unsigned integer and
// returns the result as a uint32 along with the number of bytes actually read.
//
// An UnmarshalError is returned if there are insufficient bytes remaining.
//
// Reference:
// RFC Section 4.2 - Unsigned Integer
// 32-bit big-endian unsigned integer in range [0, 4294967295]
func (d *Decoder) DecodeUint() (uint32, int, error) {
var buf [4]byte
n, err := io.ReadFull(d.r, buf[:])
if err != nil {
msg := fmt.Sprintf(errIODecode, err.Error(), 4)
err := unmarshalError("DecodeUint", ErrIO, msg, buf[:n], err)
return 0, n, err
}
rv := uint32(buf[3]) | uint32(buf[2])<<8 |
uint32(buf[1])<<16 | uint32(buf[0])<<24
return rv, n, nil
}
// DecodeEnum treats the next 4 bytes as an XDR encoded enumeration value and
// returns the result as an int32 after verifying that the value is in the
// provided map of valid values. It also returns the number of bytes actually
// read.
//
// An UnmarshalError is returned if there are insufficient bytes remaining or
// the parsed enumeration value is not one of the provided valid values.
//
// Reference:
// RFC Section 4.3 - Enumeration
// Represented as an XDR encoded signed integer
func (d *Decoder) DecodeEnum(validEnums map[int32]bool) (int32, int, error) {
val, n, err := d.DecodeInt()
if err != nil {
return 0, n, err
}
if !validEnums[val] {
err := unmarshalError("DecodeEnum", ErrBadEnumValue,
"invalid enum", val, nil)
return 0, n, err
}
return val, n, nil
}
// DecodeBool treats the next 4 bytes as an XDR encoded boolean value and
// returns the result as a bool along with the number of bytes actually read.
//
// An UnmarshalError is returned if there are insufficient bytes remaining or
// the parsed value is not a 0 or 1.
//
// Reference:
// RFC Section 4.4 - Boolean
// Represented as an XDR encoded enumeration where 0 is false and 1 is true
func (d *Decoder) DecodeBool() (bool, int, error) {
val, n, err := d.DecodeInt()
if err != nil {
return false, n, err
}
switch val {
case 0:
return false, n, nil
case 1:
return true, n, nil
}
err = unmarshalError("DecodeBool", ErrBadEnumValue, "bool not 0 or 1",
val, nil)
return false, n, err
}
// DecodeHyper treats the next 8 bytes as an XDR encoded hyper value and
// returns the result as an int64 along with the number of bytes actually read.
//
// An UnmarshalError is returned if there are insufficient bytes remaining.
//
// Reference:
// RFC Section 4.5 - Hyper Integer
// 64-bit big-endian signed integer in range [-9223372036854775808, 9223372036854775807]
func (d *Decoder) DecodeHyper() (int64, int, error) {
var buf [8]byte
n, err := io.ReadFull(d.r, buf[:])
if err != nil {
msg := fmt.Sprintf(errIODecode, err.Error(), 8)
err := unmarshalError("DecodeHyper", ErrIO, msg, buf[:n], err)
return 0, n, err
}
rv := int64(buf[7]) | int64(buf[6])<<8 |
int64(buf[5])<<16 | int64(buf[4])<<24 |
int64(buf[3])<<32 | int64(buf[2])<<40 |
int64(buf[1])<<48 | int64(buf[0])<<56
return rv, n, err
}
// DecodeUhyper treats the next 8 bytes as an XDR encoded unsigned hyper value
// and returns the result as a uint64 along with the number of bytes actually
// read.
//
// An UnmarshalError is returned if there are insufficient bytes remaining.
//
// Reference:
// RFC Section 4.5 - Unsigned Hyper Integer
// 64-bit big-endian unsigned integer in range [0, 18446744073709551615]
func (d *Decoder) DecodeUhyper() (uint64, int, error) {
var buf [8]byte
n, err := io.ReadFull(d.r, buf[:])
if err != nil {
msg := fmt.Sprintf(errIODecode, err.Error(), 8)
err := unmarshalError("DecodeUhyper", ErrIO, msg, buf[:n], err)
return 0, n, err
}
rv := uint64(buf[7]) | uint64(buf[6])<<8 |
uint64(buf[5])<<16 | uint64(buf[4])<<24 |
uint64(buf[3])<<32 | uint64(buf[2])<<40 |
uint64(buf[1])<<48 | uint64(buf[0])<<56
return rv, n, nil
}
// DecodeFloat treats the next 4 bytes as an XDR encoded floating point and
// returns the result as a float32 along with the number of bytes actually read.
//
// An UnmarshalError is returned if there are insufficient bytes remaining.
//
// Reference:
// RFC Section 4.6 - Floating Point
// 32-bit single-precision IEEE 754 floating point
func (d *Decoder) DecodeFloat() (float32, int, error) {
var buf [4]byte
n, err := io.ReadFull(d.r, buf[:])
if err != nil {
msg := fmt.Sprintf(errIODecode, err.Error(), 4)
err := unmarshalError("DecodeFloat", ErrIO, msg, buf[:n], err)
return 0, n, err
}
val := uint32(buf[3]) | uint32(buf[2])<<8 |
uint32(buf[1])<<16 | uint32(buf[0])<<24
return math.Float32frombits(val), n, nil
}
// DecodeDouble treats the next 8 bytes as an XDR encoded double-precision
// floating point and returns the result as a float64 along with the number of
// bytes actually read.
//
// An UnmarshalError is returned if there are insufficient bytes remaining.
//
// Reference:
// RFC Section 4.7 - Double-Precision Floating Point
// 64-bit double-precision IEEE 754 floating point
func (d *Decoder) DecodeDouble() (float64, int, error) {
var buf [8]byte
n, err := io.ReadFull(d.r, buf[:])
if err != nil {
msg := fmt.Sprintf(errIODecode, err.Error(), 8)
err := unmarshalError("DecodeDouble", ErrIO, msg, buf[:n], err)
return 0, n, err
}
val := uint64(buf[7]) | uint64(buf[6])<<8 |
uint64(buf[5])<<16 | uint64(buf[4])<<24 |
uint64(buf[3])<<32 | uint64(buf[2])<<40 |
uint64(buf[1])<<48 | uint64(buf[0])<<56
return math.Float64frombits(val), n, nil
}
// RFC Section 4.8 - Quadruple-Precision Floating Point
// 128-bit quadruple-precision floating point
// Not Implemented
// DecodeFixedOpaque treats the next 'size' bytes as XDR encoded opaque data and
// returns the result as a byte slice along with the number of bytes actually
// read.
//
// An UnmarshalError is returned if there are insufficient bytes remaining to
// satisfy the passed size, including the necessary padding to make it a
// multiple of 4.
//
// Reference:
// RFC Section 4.9 - Fixed-Length Opaque Data
// Fixed-length uninterpreted data zero-padded to a multiple of four
func (d *Decoder) DecodeFixedOpaque(size int32) ([]byte, int, error) {
// Nothing to do if size is 0.
if size == 0 {
return nil, 0, nil
}
pad := (4 - (size % 4)) % 4
paddedSize := size + pad
if uint(paddedSize) > uint(math.MaxInt32) {
err := unmarshalError("DecodeFixedOpaque", ErrOverflow,
errMaxSlice, paddedSize, nil)
return nil, 0, err
}
buf := make([]byte, paddedSize)
n, err := io.ReadFull(d.r, buf)
if err != nil {
msg := fmt.Sprintf(errIODecode, err.Error(), paddedSize)
err := unmarshalError("DecodeFixedOpaque", ErrIO, msg, buf[:n],
err)
return nil, n, err
}
return buf[0:size], n, nil
}
// DecodeOpaque treats the next bytes as variable length XDR encoded opaque
// data and returns the result as a byte slice along with the number of bytes
// actually read.
//
// An UnmarshalError is returned if there are insufficient bytes remaining or
// the opaque data is larger than the max length of a Go slice.
//
// Reference:
// RFC Section 4.10 - Variable-Length Opaque Data
// Unsigned integer length followed by fixed opaque data of that length
func (d *Decoder) DecodeOpaque() ([]byte, int, error) {
dataLen, n, err := d.DecodeUint()
if err != nil {
return nil, n, err
}
if uint(dataLen) > uint(math.MaxInt32) ||
(d.maxReadSize != 0 && uint(dataLen) > d.maxReadSize) {
err := unmarshalError("DecodeOpaque", ErrOverflow, errMaxSlice,
dataLen, nil)
return nil, n, err
}
rv, n2, err := d.DecodeFixedOpaque(int32(dataLen))
n += n2
if err != nil {
return nil, n, err
}
return rv, n, nil
}
// DecodeString treats the next bytes as a variable length XDR encoded string
// and returns the result as a string along with the number of bytes actually
// read. Character encoding is assumed to be UTF-8 and therefore ASCII
// compatible. If the underlying character encoding is not compatibile with
// this assumption, the data can instead be read as variable-length opaque data
// (DecodeOpaque) and manually converted as needed.
//
// An UnmarshalError is returned if there are insufficient bytes remaining or
// the string data is larger than the max length of a Go slice.
//
// Reference:
// RFC Section 4.11 - String
// Unsigned integer length followed by bytes zero-padded to a multiple of
// four
func (d *Decoder) DecodeString() (string, int, error) {
dataLen, n, err := d.DecodeUint()
if err != nil {
return "", n, err
}
if uint(dataLen) > uint(math.MaxInt32) ||
(d.maxReadSize != 0 && uint(dataLen) > d.maxReadSize) {
err = unmarshalError("DecodeString", ErrOverflow, errMaxSlice,
dataLen, nil)
return "", n, err
}
opaque, n2, err := d.DecodeFixedOpaque(int32(dataLen))
n += n2
if err != nil {
return "", n, err
}
return string(opaque), n, nil
}
// decodeFixedArray treats the next bytes as a series of XDR encoded elements
// of the same type as the array represented by the reflection value and decodes
// each element into the passed array. The ignoreOpaque flag controls whether
// or not uint8 (byte) elements should be decoded individually or as a fixed
// sequence of opaque data. It returns the the number of bytes actually read.
//
// An UnmarshalError is returned if any issues are encountered while decoding
// the array elements.
//
// Reference:
// RFC Section 4.12 - Fixed-Length Array
// Individually XDR encoded array elements
func (d *Decoder) decodeFixedArray(v reflect.Value, ignoreOpaque bool) (int, error) {
// Treat [#]byte (byte is alias for uint8) as opaque data unless
// ignored.
if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 {
data, n, err := d.DecodeFixedOpaque(int32(v.Len()))
if err != nil {
return n, err
}
reflect.Copy(v, reflect.ValueOf(data))
return n, nil
}
// Decode each array element.
var n int
for i := 0; i < v.Len(); i++ {
n2, err := d.decode(v.Index(i))
n += n2
if err != nil {
return n, err
}
}
return n, nil
}
// decodeArray treats the next bytes as a variable length series of XDR encoded
// elements of the same type as the array represented by the reflection value.
// The number of elements is obtained by first decoding the unsigned integer
// element count. Then each element is decoded into the passed array. The
// ignoreOpaque flag controls whether or not uint8 (byte) elements should be
// decoded individually or as a variable sequence of opaque data. It returns
// the number of bytes actually read.
//
// An UnmarshalError is returned if any issues are encountered while decoding
// the array elements.
//
// Reference:
// RFC Section 4.13 - Variable-Length Array
// Unsigned integer length followed by individually XDR encoded array
// elements
func (d *Decoder) decodeArray(v reflect.Value, ignoreOpaque bool) (int, error) {
dataLen, n, err := d.DecodeUint()
if err != nil {
return n, err
}
if uint(dataLen) > uint(math.MaxInt32) ||
(d.maxReadSize != 0 && uint(dataLen) > d.maxReadSize) {
err := unmarshalError("decodeArray", ErrOverflow, errMaxSlice,
dataLen, nil)
return n, err
}
// Allocate storage for the slice elements (the underlying array) if
// existing slice does not have enough capacity.
sliceLen := int(dataLen)
if v.Cap() < sliceLen {
v.Set(reflect.MakeSlice(v.Type(), sliceLen, sliceLen))
}
if v.Len() < sliceLen {
v.SetLen(sliceLen)
}
// Treat []byte (byte is alias for uint8) as opaque data unless ignored.
if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 {
data, n2, err := d.DecodeFixedOpaque(int32(sliceLen))
n += n2
if err != nil {
return n, err
}
v.SetBytes(data)
return n, nil
}
// Decode each slice element.
for i := 0; i < sliceLen; i++ {
n2, err := d.decode(v.Index(i))
n += n2
if err != nil {
return n, err
}
}
return n, nil
}
// decodeStruct treats the next bytes as a series of XDR encoded elements
// of the same type as the exported fields of the struct represented by the
// passed reflection value. Pointers are automatically indirected and
// allocated as necessary. It returns the the number of bytes actually read.
//
// An UnmarshalError is returned if any issues are encountered while decoding
// the elements.
//
// Reference:
// RFC Section 4.14 - Structure
// XDR encoded elements in the order of their declaration in the struct
func (d *Decoder) decodeStruct(v reflect.Value) (int, error) {
var n int
vt := v.Type()
for i := 0; i < v.NumField(); i++ {
// Skip unexported fields.
vtf := vt.Field(i)
if vtf.PkgPath != "" {
continue
}
// Indirect through pointers allocating them as needed and
// ensure the field is settable.
vf := v.Field(i)
vf, err := d.indirect(vf)
if err != nil {
return n, err
}
if !vf.CanSet() {
msg := fmt.Sprintf("can't decode to unsettable '%v'",
vf.Type().String())
err := unmarshalError("decodeStruct", ErrNotSettable,
msg, nil, nil)
return n, err
}
// Handle non-opaque data to []uint8 and [#]uint8 based on
// struct tag.
tag := vtf.Tag.Get("xdropaque")
if tag == "false" {
switch vf.Kind() {
case reflect.Slice:
n2, err := d.decodeArray(vf, true)
n += n2
if err != nil {
return n, err
}
continue
case reflect.Array:
n2, err := d.decodeFixedArray(vf, true)
n += n2
if err != nil {
return n, err
}
continue
}
}
// Decode each struct field.
n2, err := d.decode(vf)
n += n2
if err != nil {
return n, err
}
}
return n, nil
}
// RFC Section 4.15 - Discriminated Union
// RFC Section 4.16 - Void
// RFC Section 4.17 - Constant
// RFC Section 4.18 - Typedef
// RFC Section 4.19 - Optional data
// RFC Sections 4.15 though 4.19 only apply to the data specification language
// which is not implemented by this package. In the case of discriminated
// unions, struct tags are used to perform a similar function.
// decodeMap treats the next bytes as an XDR encoded variable array of 2-element
// structures whose fields are of the same type as the map keys and elements
// represented by the passed reflection value. Pointers are automatically
// indirected and allocated as necessary. It returns the the number of bytes
// actually read.
//
// An UnmarshalError is returned if any issues are encountered while decoding
// the elements.
func (d *Decoder) decodeMap(v reflect.Value) (int, error) {
dataLen, n, err := d.DecodeUint()
if err != nil {
return n, err
}
// Allocate storage for the underlying map if needed.
vt := v.Type()
if v.IsNil() {
v.Set(reflect.MakeMap(vt))
}
// Decode each key and value according to their type.
keyType := vt.Key()
elemType := vt.Elem()
for i := uint32(0); i < dataLen; i++ {
key := reflect.New(keyType).Elem()
n2, err := d.decode(key)
n += n2
if err != nil {
return n, err
}
val := reflect.New(elemType).Elem()
n2, err = d.decode(val)
n += n2
if err != nil {
return n, err
}
v.SetMapIndex(key, val)
}
return n, nil
}
// decodeInterface examines the interface represented by the passed reflection
// value to detect whether it is an interface that can be decoded into and
// if it is, extracts the underlying value to pass back into the decode function
// for decoding according to its type. It returns the the number of bytes
// actually read.
//
// An UnmarshalError is returned if any issues are encountered while decoding
// the interface.
func (d *Decoder) decodeInterface(v reflect.Value) (int, error) {
if v.IsNil() || !v.CanInterface() {
msg := fmt.Sprintf("can't decode to nil interface")
err := unmarshalError("decodeInterface", ErrNilInterface, msg,
nil, nil)
return 0, err
}
// Extract underlying value from the interface and indirect through
// pointers allocating them as needed.
ve := reflect.ValueOf(v.Interface())
ve, err := d.indirect(ve)
if err != nil {
return 0, err
}
if !ve.CanSet() {
msg := fmt.Sprintf("can't decode to unsettable '%v'",
ve.Type().String())
err := unmarshalError("decodeInterface", ErrNotSettable, msg,
nil, nil)
return 0, err
}
return d.decode(ve)
}
// decode is the main workhorse for unmarshalling via reflection. It uses
// the passed reflection value to choose the XDR primitives to decode from
// the encapsulated reader. It is a recursive function,
// so cyclic data structures are not supported and will result in an infinite
// loop. It returns the the number of bytes actually read.
func (d *Decoder) decode(v reflect.Value) (int, error) {
if !v.IsValid() {
msg := fmt.Sprintf("type '%s' is not valid", v.Kind().String())
err := unmarshalError("decode", ErrUnsupportedType, msg, nil, nil)
return 0, err
}
// Indirect through pointers allocating them as needed.
ve, err := d.indirect(v)
if err != nil {
return 0, err
}
// Handle time.Time values by decoding them as an RFC3339 formatted
// string with nanosecond precision. Check the type string rather
// than doing a full blown conversion to interface and type assertion
// since checking a string is much quicker.
switch ve.Type().String() {
case "time.Time":
// Read the value as a string and parse it.
timeString, n, err := d.DecodeString()
if err != nil {
return n, err
}
ttv, err := time.Parse(time.RFC3339, timeString)
if err != nil {
err := unmarshalError("decode", ErrParseTime,
err.Error(), timeString, err)
return n, err
}
ve.Set(reflect.ValueOf(ttv))
return n, nil
}
// If this type is in our custom types map, call the decode routine set up
// for it.
if dt, ok := d.customTypes[ve.Type().String()]; ok {
return dt.Decode(d, v)
}
// Handle native Go types.
switch ve.Kind() {
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int:
i, n, err := d.DecodeInt()
if err != nil {
return n, err
}
if ve.OverflowInt(int64(i)) {
msg := fmt.Sprintf("signed integer too large to fit '%s'",
ve.Kind().String())
err = unmarshalError("decode", ErrOverflow, msg, i, nil)
return n, err
}
ve.SetInt(int64(i))
return n, nil
case reflect.Int64:
i, n, err := d.DecodeHyper()
if err != nil {
return n, err
}
ve.SetInt(i)
return n, nil
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint:
ui, n, err := d.DecodeUint()
if err != nil {
return n, err
}
if ve.OverflowUint(uint64(ui)) {
msg := fmt.Sprintf("unsigned integer too large to fit '%s'",
ve.Kind().String())
err = unmarshalError("decode", ErrOverflow, msg, ui, nil)
return n, err
}
ve.SetUint(uint64(ui))
return n, nil
case reflect.Uint64:
ui, n, err := d.DecodeUhyper()
if err != nil {
return n, err
}
ve.SetUint(ui)
return n, nil
case reflect.Bool:
b, n, err := d.DecodeBool()
if err != nil {
return n, err
}
ve.SetBool(b)
return n, nil
case reflect.Float32:
f, n, err := d.DecodeFloat()
if err != nil {
return n, err
}
ve.SetFloat(float64(f))
return n, nil
case reflect.Float64:
f, n, err := d.DecodeDouble()
if err != nil {
return n, err
}
ve.SetFloat(f)
return n, nil
case reflect.String:
s, n, err := d.DecodeString()
if err != nil {
return n, err
}
ve.SetString(s)
return n, nil
case reflect.Array:
n, err := d.decodeFixedArray(ve, false)
if err != nil {
return n, err
}
return n, nil
case reflect.Slice:
n, err := d.decodeArray(ve, false)
if err != nil {
return n, err
}
return n, nil
case reflect.Struct:
n, err := d.decodeStruct(ve)
if err != nil {
return n, err
}
return n, nil
case reflect.Map:
n, err := d.decodeMap(ve)
if err != nil {
return n, err
}
return n, nil
case reflect.Interface:
n, err := d.decodeInterface(ve)
if err != nil {
return n, err
}
return n, nil
}
// The only unhandled types left are unsupported. At the time of this
// writing the only remaining unsupported types that exist are
// reflect.Uintptr and reflect.UnsafePointer.
msg := fmt.Sprintf("unsupported Go type '%s'", ve.Kind().String())
err = unmarshalError("decode", ErrUnsupportedType, msg, nil, nil)
return 0, err
}
// indirect dereferences pointers allocating them as needed until it reaches
// a non-pointer. This allows transparent decoding through arbitrary levels
// of indirection.
func (d *Decoder) indirect(v reflect.Value) (reflect.Value, error) {
rv := v
for rv.Kind() == reflect.Ptr {
// Allocate pointer if needed.
isNil := rv.IsNil()
if isNil && !rv.CanSet() {
msg := fmt.Sprintf("unable to allocate pointer for '%v'",
rv.Type().String())
err := unmarshalError("indirect", ErrNotSettable, msg,
nil, nil)
return rv, err
}
if isNil {
rv.Set(reflect.New(rv.Type().Elem()))
}
rv = rv.Elem()
}
return rv, nil
}
// Decode operates identically to the Unmarshal function with the exception of
// using the reader associated with the Decoder as the source of XDR-encoded
// data instead of a user-supplied reader. See the Unmarhsal documentation for
// specifics.
func (d *Decoder) Decode(v interface{}) (int, error) {
if v == nil {
msg := "can't unmarshal to nil interface"
return 0, unmarshalError("Unmarshal", ErrNilInterface, msg, nil,
nil)
}
vv := reflect.ValueOf(v)
if vv.Kind() != reflect.Ptr {
msg := fmt.Sprintf("can't unmarshal to non-pointer '%v' - use "+
"& operator", vv.Type().String())
err := unmarshalError("Unmarshal", ErrBadArguments, msg, nil, nil)
return 0, err
}
if vv.IsNil() && !vv.CanSet() {
msg := fmt.Sprintf("can't unmarshal to unsettable '%v' - use "+
"& operator", vv.Type().String())
err := unmarshalError("Unmarshal", ErrNotSettable, msg, nil, nil)
return 0, err
}
return d.decode(vv)
}
// NewDecoder returns a Decoder that can be used to manually decode XDR data
// from a provided reader. Typically, Unmarshal should be used instead of
// manually creating a Decoder.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{r: r}
}
// NewDecoderLimited is identical to NewDecoder but it sets maxReadSize in
// order to cap reads.
func NewDecoderLimited(r io.Reader, maxSize uint) *Decoder {
return &Decoder{r: r, maxReadSize: maxSize}
}
// NewDecoderCustomTypes returns a decoder with support for custom types known
// to the caller. The second parameter is a map of the type name to the decoder
// routine. When the decoder finds a type matching one of the entries in the map
// it will call the custom routine for that type.
func NewDecoderCustomTypes(r io.Reader, maxSize uint, ct map[string]TypeDecoder) *Decoder {
return &Decoder{r: r, maxReadSize: maxSize, customTypes: ct}
}

View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
Package xdr implements the data representation portion of the External Data
Representation (XDR) standard protocol as specified in RFC 4506 (obsoletes
RFC 1832 and RFC 1014).
The XDR RFC defines both a data specification language and a data
representation standard. This package implements methods to encode and decode
XDR data per the data representation standard with the exception of 128-bit
quadruple-precision floating points. It does not currently implement parsing of
the data specification language. In other words, the ability to automatically
generate Go code by parsing an XDR data specification file (typically .x
extension) is not supported. In practice, this limitation of the package is
fairly minor since it is largely unnecessary due to the reflection capabilities
of Go as described below.
This package provides two approaches for encoding and decoding XDR data:
1) Marshal/Unmarshal functions which automatically map between XDR and Go types
2) Individual Encoder/Decoder objects to manually work with XDR primitives
For the Marshal/Unmarshal functions, Go reflection capabilities are used to
choose the type of the underlying XDR data based upon the Go type to encode or
the target Go type to decode into. A description of how each type is mapped is
provided below, however one important type worth reviewing is Go structs. In
the case of structs, each exported field (first letter capitalized) is reflected
and mapped in order. As a result, this means a Go struct with exported fields
of the appropriate types listed in the expected order can be used to
automatically encode / decode the XDR data thereby eliminating the need to write
a lot of boilerplate code to encode/decode and error check each piece of XDR
data as is typically required with C based XDR libraries.
Go Type to XDR Type Mappings
The following chart shows an overview of how Go types are mapped to XDR types
for automatic marshalling and unmarshalling. The documentation for the Marshal
and Unmarshal functions has specific details of how the mapping proceeds.
Go Type <-> XDR Type
--------------------
int8, int16, int32, int <-> XDR Integer
uint8, uint16, uint32, uint <-> XDR Unsigned Integer
int64 <-> XDR Hyper Integer
uint64 <-> XDR Unsigned Hyper Integer
bool <-> XDR Boolean
float32 <-> XDR Floating-Point
float64 <-> XDR Double-Precision Floating-Point
string <-> XDR String
byte <-> XDR Integer
[]byte <-> XDR Variable-Length Opaque Data
[#]byte <-> XDR Fixed-Length Opaque Data
[]<type> <-> XDR Variable-Length Array
[#]<type> <-> XDR Fixed-Length Array
struct <-> XDR Structure
map <-> XDR Variable-Length Array of two-element XDR Structures
time.Time <-> XDR String encoded with RFC3339 nanosecond precision
Notes and Limitations:
* Automatic marshalling and unmarshalling of variable and fixed-length
arrays of uint8s require a special struct tag `xdropaque:"false"`
since byte slices and byte arrays are assumed to be opaque data and
byte is a Go alias for uint8 thus indistinguishable under reflection
* Channel, complex, and function types cannot be encoded
* Interfaces without a concrete value cannot be encoded
* Cyclic data structures are not supported and will result in infinite
loops
* Strings are marshalled and unmarshalled with UTF-8 character encoding
which differs from the XDR specification of ASCII, however UTF-8 is
backwards compatible with ASCII so this should rarely cause issues
Encoding
To encode XDR data, use the Marshal function.
func Marshal(w io.Writer, v interface{}) (int, error)
For example, given the following code snippet:
type ImageHeader struct {
Signature [3]byte
Version uint32
IsGrayscale bool
NumSections uint32
}
h := ImageHeader{[3]byte{0xAB, 0xCD, 0xEF}, 2, true, 10}
var w bytes.Buffer
bytesWritten, err := xdr.Marshal(&w, &h)
// Error check elided
The result, encodedData, will then contain the following XDR encoded byte
sequence:
0xAB, 0xCD, 0xEF, 0x00,
0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x0A
In addition, while the automatic marshalling discussed above will work for the
vast majority of cases, an Encoder object is provided that can be used to
manually encode XDR primitives for complex scenarios where automatic
reflection-based encoding won't work. The included examples provide a sample of
manual usage via an Encoder.
Decoding
To decode XDR data, use the Unmarshal function.
func Unmarshal(r io.Reader, v interface{}) (int, error)
For example, given the following code snippet:
type ImageHeader struct {
Signature [3]byte
Version uint32
IsGrayscale bool
NumSections uint32
}
// Using output from the Encoding section above.
encodedData := []byte{
0xAB, 0xCD, 0xEF, 0x00,
0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x0A,
}
var h ImageHeader
bytesRead, err := xdr.Unmarshal(bytes.NewReader(encodedData), &h)
// Error check elided
The struct instance, h, will then contain the following values:
h.Signature = [3]byte{0xAB, 0xCD, 0xEF}
h.Version = 2
h.IsGrayscale = true
h.NumSections = 10
In addition, while the automatic unmarshalling discussed above will work for the
vast majority of cases, a Decoder object is provided that can be used to
manually decode XDR primitives for complex scenarios where automatic
reflection-based decoding won't work. The included examples provide a sample of
manual usage via a Decoder.
Errors
All errors are either of type UnmarshalError or MarshalError. Both provide
human-readable output as well as an ErrorCode field which can be inspected by
sophisticated callers if necessary.
See the documentation of UnmarshalError, MarshalError, and ErrorCode for further
details.
*/
package xdr

View File

@ -0,0 +1,669 @@
/*
* Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package xdr
import (
"fmt"
"io"
"math"
"reflect"
"time"
)
var errIOEncode = "%s while encoding %d bytes"
/*
Marshal writes the XDR encoding of v to writer w and returns the number of bytes
written. It traverses v recursively and automatically indirects pointers
through arbitrary depth to encode the actual value pointed to.
Marshal uses reflection to determine the type of the concrete value contained by
v and performs a mapping of Go types to the underlying XDR types as follows:
Go Type -> XDR Type
--------------------
int8, int16, int32, int -> XDR Integer
uint8, uint16, uint32, uint -> XDR Unsigned Integer
int64 -> XDR Hyper Integer
uint64 -> XDR Unsigned Hyper Integer
bool -> XDR Boolean
float32 -> XDR Floating-Point
float64 -> XDR Double-Precision Floating-Point
string -> XDR String
byte -> XDR Integer
[]byte -> XDR Variable-Length Opaque Data
[#]byte -> XDR Fixed-Length Opaque Data
[]<type> -> XDR Variable-Length Array
[#]<type> -> XDR Fixed-Length Array
struct -> XDR Structure
map -> XDR Variable-Length Array of two-element XDR Structures
time.Time -> XDR String encoded with RFC3339 nanosecond precision
Notes and Limitations:
* Automatic marshalling of variable and fixed-length arrays of uint8s
requires a special struct tag `xdropaque:"false"` since byte slices and
byte arrays are assumed to be opaque data and byte is a Go alias for uint8
thus indistinguishable under reflection
* Channel, complex, and function types cannot be encoded
* Interfaces without a concrete value cannot be encoded
* Cyclic data structures are not supported and will result in infinite loops
* Strings are marshalled with UTF-8 character encoding which differs from
the XDR specification of ASCII, however UTF-8 is backwards compatible with
ASCII so this should rarely cause issues
If any issues are encountered during the marshalling process, a MarshalError is
returned with a human readable description as well as an ErrorCode value for
further inspection from sophisticated callers. Some potential issues are
unsupported Go types, attempting to encode more opaque data than can be
represented by a single opaque XDR entry, and exceeding max slice limitations.
*/
func Marshal(w io.Writer, v interface{}) (int, error) {
enc := Encoder{w: w}
return enc.Encode(v)
}
// An Encoder wraps an io.Writer that will receive the XDR encoded byte stream.
// See NewEncoder.
type Encoder struct {
w io.Writer
}
// EncodeInt writes the XDR encoded representation of the passed 32-bit signed
// integer to the encapsulated writer and returns the number of bytes written.
//
// A MarshalError with an error code of ErrIO is returned if writing the data
// fails.
//
// Reference:
// RFC Section 4.1 - Integer
// 32-bit big-endian signed integer in range [-2147483648, 2147483647]
func (enc *Encoder) EncodeInt(v int32) (int, error) {
var b [4]byte
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
n, err := enc.w.Write(b[:])
if err != nil {
msg := fmt.Sprintf(errIOEncode, err.Error(), 4)
err := marshalError("EncodeInt", ErrIO, msg, b[:n], err)
return n, err
}
return n, nil
}
// EncodeUint writes the XDR encoded representation of the passed 32-bit
// unsigned integer to the encapsulated writer and returns the number of bytes
// written.
//
// A MarshalError with an error code of ErrIO is returned if writing the data
// fails.
//
// Reference:
// RFC Section 4.2 - Unsigned Integer
// 32-bit big-endian unsigned integer in range [0, 4294967295]
func (enc *Encoder) EncodeUint(v uint32) (int, error) {
var b [4]byte
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
n, err := enc.w.Write(b[:])
if err != nil {
msg := fmt.Sprintf(errIOEncode, err.Error(), 4)
err := marshalError("EncodeUint", ErrIO, msg, b[:n], err)
return n, err
}
return n, nil
}
// EncodeEnum treats the passed 32-bit signed integer as an enumeration value
// and, if it is in the list of passed valid enumeration values, writes the XDR
// encoded representation of it to the encapsulated writer. It returns the
// number of bytes written.
//
// A MarshalError is returned if the enumeration value is not one of the
// provided valid values or if writing the data fails.
//
// Reference:
// RFC Section 4.3 - Enumeration
// Represented as an XDR encoded signed integer
func (enc *Encoder) EncodeEnum(v int32, validEnums map[int32]bool) (int, error) {
if !validEnums[v] {
err := marshalError("EncodeEnum", ErrBadEnumValue,
"invalid enum", v, nil)
return 0, err
}
return enc.EncodeInt(v)
}
// EncodeBool writes the XDR encoded representation of the passed boolean to the
// encapsulated writer and returns the number of bytes written.
//
// A MarshalError with an error code of ErrIO is returned if writing the data
// fails.
//
// Reference:
// RFC Section 4.4 - Boolean
// Represented as an XDR encoded enumeration where 0 is false and 1 is true
func (enc *Encoder) EncodeBool(v bool) (int, error) {
i := int32(0)
if v == true {
i = 1
}
return enc.EncodeInt(i)
}
// EncodeHyper writes the XDR encoded representation of the passed 64-bit
// signed integer to the encapsulated writer and returns the number of bytes
// written.
//
// A MarshalError with an error code of ErrIO is returned if writing the data
// fails.
//
// Reference:
// RFC Section 4.5 - Hyper Integer
// 64-bit big-endian signed integer in range [-9223372036854775808, 9223372036854775807]
func (enc *Encoder) EncodeHyper(v int64) (int, error) {
var b [8]byte
b[0] = byte(v >> 56)
b[1] = byte(v >> 48)
b[2] = byte(v >> 40)
b[3] = byte(v >> 32)
b[4] = byte(v >> 24)
b[5] = byte(v >> 16)
b[6] = byte(v >> 8)
b[7] = byte(v)
n, err := enc.w.Write(b[:])
if err != nil {
msg := fmt.Sprintf(errIOEncode, err.Error(), 8)
err := marshalError("EncodeHyper", ErrIO, msg, b[:n], err)
return n, err
}
return n, nil
}
// EncodeUhyper writes the XDR encoded representation of the passed 64-bit
// unsigned integer to the encapsulated writer and returns the number of bytes
// written.
//
// A MarshalError with an error code of ErrIO is returned if writing the data
// fails.
//
// Reference:
// RFC Section 4.5 - Unsigned Hyper Integer
// 64-bit big-endian unsigned integer in range [0, 18446744073709551615]
func (enc *Encoder) EncodeUhyper(v uint64) (int, error) {
var b [8]byte
b[0] = byte(v >> 56)
b[1] = byte(v >> 48)
b[2] = byte(v >> 40)
b[3] = byte(v >> 32)
b[4] = byte(v >> 24)
b[5] = byte(v >> 16)
b[6] = byte(v >> 8)
b[7] = byte(v)
n, err := enc.w.Write(b[:])
if err != nil {
msg := fmt.Sprintf(errIOEncode, err.Error(), 8)
err := marshalError("EncodeUhyper", ErrIO, msg, b[:n], err)
return n, err
}
return n, nil
}
// EncodeFloat writes the XDR encoded representation of the passed 32-bit
// (single-precision) floating point to the encapsulated writer and returns the
// number of bytes written.
//
// A MarshalError with an error code of ErrIO is returned if writing the data
// fails.
//
// Reference:
// RFC Section 4.6 - Floating Point
// 32-bit single-precision IEEE 754 floating point
func (enc *Encoder) EncodeFloat(v float32) (int, error) {
ui := math.Float32bits(v)
return enc.EncodeUint(ui)
}
// EncodeDouble writes the XDR encoded representation of the passed 64-bit
// (double-precision) floating point to the encapsulated writer and returns the
// number of bytes written.
//
// A MarshalError with an error code of ErrIO is returned if writing the data
// fails.
//
// Reference:
// RFC Section 4.7 - Double-Precision Floating Point
// 64-bit double-precision IEEE 754 floating point
func (enc *Encoder) EncodeDouble(v float64) (int, error) {
ui := math.Float64bits(v)
return enc.EncodeUhyper(ui)
}
// RFC Section 4.8 - Quadruple-Precision Floating Point
// 128-bit quadruple-precision floating point
// Not Implemented
// EncodeFixedOpaque treats the passed byte slice as opaque data of a fixed
// size and writes the XDR encoded representation of it to the encapsulated
// writer. It returns the number of bytes written.
//
// A MarshalError with an error code of ErrIO is returned if writing the data
// fails.
//
// Reference:
// RFC Section 4.9 - Fixed-Length Opaque Data
// Fixed-length uninterpreted data zero-padded to a multiple of four
func (enc *Encoder) EncodeFixedOpaque(v []byte) (int, error) {
l := len(v)
pad := (4 - (l % 4)) % 4
// Write the actual bytes.
n, err := enc.w.Write(v)
if err != nil {
msg := fmt.Sprintf(errIOEncode, err.Error(), len(v))
err := marshalError("EncodeFixedOpaque", ErrIO, msg, v[:n], err)
return n, err
}
// Write any padding if needed.
if pad > 0 {
b := make([]byte, pad)
n2, err := enc.w.Write(b)
n += n2
if err != nil {
written := make([]byte, l+n2)
copy(written, v)
copy(written[l:], b[:n2])
msg := fmt.Sprintf(errIOEncode, err.Error(), l+pad)
err := marshalError("EncodeFixedOpaque", ErrIO, msg,
written, err)
return n, err
}
}
return n, nil
}
// EncodeOpaque treats the passed byte slice as opaque data of a variable
// size and writes the XDR encoded representation of it to the encapsulated
// writer. It returns the number of bytes written.
//
// A MarshalError with an error code of ErrIO is returned if writing the data
// fails.
//
// Reference:
// RFC Section 4.10 - Variable-Length Opaque Data
// Unsigned integer length followed by fixed opaque data of that length
func (enc *Encoder) EncodeOpaque(v []byte) (int, error) {
// Length of opaque data.
n, err := enc.EncodeUint(uint32(len(v)))
if err != nil {
return n, err
}
n2, err := enc.EncodeFixedOpaque(v)
n += n2
return n, err
}
// EncodeString writes the XDR encoded representation of the passed string
// to the encapsulated writer and returns the number of bytes written.
// Character encoding is assumed to be UTF-8 and therefore ASCII compatible. If
// the underlying character encoding is not compatible with this assumption, the
// data can instead be written as variable-length opaque data (EncodeOpaque) and
// manually converted as needed.
//
// A MarshalError with an error code of ErrIO is returned if writing the data
// fails.
//
// Reference:
// RFC Section 4.11 - String
// Unsigned integer length followed by bytes zero-padded to a multiple of four
func (enc *Encoder) EncodeString(v string) (int, error) {
// Length of string.
n, err := enc.EncodeUint(uint32(len(v)))
if err != nil {
return n, err
}
n2, err := enc.EncodeFixedOpaque([]byte(v))
n += n2
return n, err
}
// encodeFixedArray writes the XDR encoded representation of each element
// in the passed array represented by the reflection value to the encapsulated
// writer and returns the number of bytes written. The ignoreOpaque flag
// controls whether or not uint8 (byte) elements should be encoded individually
// or as a fixed sequence of opaque data.
//
// A MarshalError is returned if any issues are encountered while encoding
// the array elements.
//
// Reference:
// RFC Section 4.12 - Fixed-Length Array
// Individually XDR encoded array elements
func (enc *Encoder) encodeFixedArray(v reflect.Value, ignoreOpaque bool) (int, error) {
// Treat [#]byte (byte is alias for uint8) as opaque data unless ignored.
if !ignoreOpaque && v.Type().Elem().Kind() == reflect.Uint8 {
// Create a slice of the underlying array for better efficiency
// when possible. Can't create a slice of an unaddressable
// value.
if v.CanAddr() {
return enc.EncodeFixedOpaque(v.Slice(0, v.Len()).Bytes())
}
// When the underlying array isn't addressable fall back to
// copying the array into a new slice. This is rather ugly, but
// the inability to create a constant slice from an
// unaddressable array is a limitation of Go.
slice := make([]byte, v.Len(), v.Len())
reflect.Copy(reflect.ValueOf(slice), v)
return enc.EncodeFixedOpaque(slice)
}
// Encode each array element.
var n int
for i := 0; i < v.Len(); i++ {
n2, err := enc.encode(v.Index(i))
n += n2
if err != nil {
return n, err
}
}
return n, nil
}
// encodeArray writes an XDR encoded integer representing the number of
// elements in the passed slice represented by the reflection value followed by
// the XDR encoded representation of each element in slice to the encapsulated
// writer and returns the number of bytes written. The ignoreOpaque flag
// controls whether or not uint8 (byte) elements should be encoded individually
// or as a variable sequence of opaque data.
//
// A MarshalError is returned if any issues are encountered while encoding
// the array elements.
//
// Reference:
// RFC Section 4.13 - Variable-Length Array
// Unsigned integer length followed by individually XDR encoded array elements
func (enc *Encoder) encodeArray(v reflect.Value, ignoreOpaque bool) (int, error) {
numItems := uint32(v.Len())
n, err := enc.EncodeUint(numItems)
if err != nil {
return n, err
}
n2, err := enc.encodeFixedArray(v, ignoreOpaque)
n += n2
return n, err
}
// encodeStruct writes an XDR encoded representation of each value in the
// exported fields of the struct represented by the passed reflection value to
// the encapsulated writer and returns the number of bytes written. Pointers
// are automatically indirected through arbitrary depth to encode the actual
// value pointed to.
//
// A MarshalError is returned if any issues are encountered while encoding
// the elements.
//
// Reference:
// RFC Section 4.14 - Structure
// XDR encoded elements in the order of their declaration in the struct
func (enc *Encoder) encodeStruct(v reflect.Value) (int, error) {
var n int
vt := v.Type()
for i := 0; i < v.NumField(); i++ {
// Skip unexported fields and indirect through pointers.
vtf := vt.Field(i)
if vtf.PkgPath != "" {
continue
}
vf := v.Field(i)
vf = enc.indirect(vf)
// Handle non-opaque data to []uint8 and [#]uint8 based on struct tag.
tag := vtf.Tag.Get("xdropaque")
if tag == "false" {
switch vf.Kind() {
case reflect.Slice:
n2, err := enc.encodeArray(vf, true)
n += n2
if err != nil {
return n, err
}
continue
case reflect.Array:
n2, err := enc.encodeFixedArray(vf, true)
n += n2
if err != nil {
return n, err
}
continue
}
}
// Encode each struct field.
n2, err := enc.encode(vf)
n += n2
if err != nil {
return n, err
}
}
return n, nil
}
// RFC Section 4.15 - Discriminated Union
// RFC Section 4.16 - Void
// RFC Section 4.17 - Constant
// RFC Section 4.18 - Typedef
// RFC Section 4.19 - Optional data
// RFC Sections 4.15 though 4.19 only apply to the data specification language
// which is not implemented by this package. In the case of discriminated
// unions, struct tags are used to perform a similar function.
// encodeMap treats the map represented by the passed reflection value as a
// variable-length array of 2-element structures whose fields are of the same
// type as the map keys and elements and writes its XDR encoded representation
// to the encapsulated writer. It returns the number of bytes written.
//
// A MarshalError is returned if any issues are encountered while encoding
// the elements.
func (enc *Encoder) encodeMap(v reflect.Value) (int, error) {
// Number of elements.
n, err := enc.EncodeUint(uint32(v.Len()))
if err != nil {
return n, err
}
// Encode each key and value according to their type.
for _, key := range v.MapKeys() {
n2, err := enc.encode(key)
n += n2
if err != nil {
return n, err
}
n2, err = enc.encode(v.MapIndex(key))
n += n2
if err != nil {
return n, err
}
}
return n, nil
}
// encodeInterface examines the interface represented by the passed reflection
// value to detect whether it is an interface that can be encoded if it is,
// extracts the underlying value to pass back into the encode function for
// encoding according to its type.
//
// A MarshalError is returned if any issues are encountered while encoding
// the interface.
func (enc *Encoder) encodeInterface(v reflect.Value) (int, error) {
if v.IsNil() || !v.CanInterface() {
msg := fmt.Sprintf("can't encode nil interface")
err := marshalError("encodeInterface", ErrNilInterface, msg,
nil, nil)
return 0, err
}
// Extract underlying value from the interface and indirect through pointers.
ve := reflect.ValueOf(v.Interface())
ve = enc.indirect(ve)
return enc.encode(ve)
}
// encode is the main workhorse for marshalling via reflection. It uses
// the passed reflection value to choose the XDR primitives to encode into
// the encapsulated writer and returns the number of bytes written. It is a
// recursive function, so cyclic data structures are not supported and will
// result in an infinite loop.
func (enc *Encoder) encode(v reflect.Value) (int, error) {
if !v.IsValid() {
msg := fmt.Sprintf("type '%s' is not valid", v.Kind().String())
err := marshalError("encode", ErrUnsupportedType, msg, nil, nil)
return 0, err
}
// Indirect through pointers to get at the concrete value.
ve := enc.indirect(v)
// Handle time.Time values by encoding them as an RFC3339 formatted
// string with nanosecond precision. Check the type string before
// doing a full blown conversion to interface and type assertion since
// checking a string is much quicker.
if ve.Type().String() == "time.Time" && ve.CanInterface() {
viface := ve.Interface()
if tv, ok := viface.(time.Time); ok {
return enc.EncodeString(tv.Format(time.RFC3339Nano))
}
}
// Handle native Go types.
switch ve.Kind() {
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int:
return enc.EncodeInt(int32(ve.Int()))
case reflect.Int64:
return enc.EncodeHyper(ve.Int())
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint:
return enc.EncodeUint(uint32(ve.Uint()))
case reflect.Uint64:
return enc.EncodeUhyper(ve.Uint())
case reflect.Bool:
return enc.EncodeBool(ve.Bool())
case reflect.Float32:
return enc.EncodeFloat(float32(ve.Float()))
case reflect.Float64:
return enc.EncodeDouble(ve.Float())
case reflect.String:
return enc.EncodeString(ve.String())
case reflect.Array:
return enc.encodeFixedArray(ve, false)
case reflect.Slice:
return enc.encodeArray(ve, false)
case reflect.Struct:
return enc.encodeStruct(ve)
case reflect.Map:
return enc.encodeMap(ve)
case reflect.Interface:
return enc.encodeInterface(ve)
}
// The only unhandled types left are unsupported. At the time of this
// writing the only remaining unsupported types that exist are
// reflect.Uintptr and reflect.UnsafePointer.
msg := fmt.Sprintf("unsupported Go type '%s'", ve.Kind().String())
err := marshalError("encode", ErrUnsupportedType, msg, nil, nil)
return 0, err
}
// indirect dereferences pointers until it reaches a non-pointer. This allows
// transparent encoding through arbitrary levels of indirection.
func (enc *Encoder) indirect(v reflect.Value) reflect.Value {
rv := v
for rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
return rv
}
// Encode operates identically to the Marshal function with the exception of
// using the writer associated with the Encoder for the destination of the
// XDR-encoded data instead of a user-supplied writer. See the Marshal
// documentation for specifics.
func (enc *Encoder) Encode(v interface{}) (int, error) {
if v == nil {
msg := "can't marshal nil interface"
err := marshalError("Marshal", ErrNilInterface, msg, nil, nil)
return 0, err
}
vv := reflect.ValueOf(v)
vve := vv
for vve.Kind() == reflect.Ptr {
if vve.IsNil() {
msg := fmt.Sprintf("can't marshal nil pointer '%v'",
vv.Type().String())
err := marshalError("Marshal", ErrBadArguments, msg,
nil, nil)
return 0, err
}
vve = vve.Elem()
}
return enc.encode(vve)
}
// NewEncoder returns an object that can be used to manually choose fields to
// XDR encode to the passed writer w. Typically, Marshal should be used instead
// of manually creating an Encoder. An Encoder, along with several of its
// methods to encode XDR primitives, is exposed so it is possible to perform
// manual encoding of data without relying on reflection should it be necessary
// in complex scenarios where automatic reflection-based encoding won't work.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{w: w}
}

View File

@ -0,0 +1,177 @@
/*
* Copyright (c) 2012-2014 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package xdr
import "fmt"
// ErrorCode identifies a kind of error.
type ErrorCode int
const (
// ErrBadArguments indicates arguments passed to the function are not
// what was expected.
ErrBadArguments ErrorCode = iota
// ErrUnsupportedType indicates the Go type is not a supported type for
// marshalling and unmarshalling XDR data.
ErrUnsupportedType
// ErrBadEnumValue indicates an enumeration value is not in the list of
// valid values.
ErrBadEnumValue
// ErrNotSettable indicates an interface value cannot be written to.
// This usually means the interface value was not passed with the &
// operator, but it can also happen if automatic pointer allocation
// fails.
ErrNotSettable
// ErrOverflow indicates that the data in question is too large to fit
// into the corresponding Go or XDR data type. For example, an integer
// decoded from XDR that is too large to fit into a target type of int8,
// or opaque data that exceeds the max length of a Go slice.
ErrOverflow
// ErrNilInterface indicates an interface with no concrete type
// information was encountered. Type information is necessary to
// perform mapping between XDR and Go types.
ErrNilInterface
// ErrIO indicates an error was encountered while reading or writing to
// an io.Reader or io.Writer, respectively. The actual underlying error
// will be available via the Err field of the MarshalError or
// UnmarshalError struct.
ErrIO
// ErrParseTime indicates an error was encountered while parsing an
// RFC3339 formatted time value. The actual underlying error will be
// available via the Err field of the UnmarshalError struct.
ErrParseTime
)
// Map of ErrorCode values back to their constant names for pretty printing.
var errorCodeStrings = map[ErrorCode]string{
ErrBadArguments: "ErrBadArguments",
ErrUnsupportedType: "ErrUnsupportedType",
ErrBadEnumValue: "ErrBadEnumValue",
ErrNotSettable: "ErrNotSettable",
ErrOverflow: "ErrOverflow",
ErrNilInterface: "ErrNilInterface",
ErrIO: "ErrIO",
ErrParseTime: "ErrParseTime",
}
// String returns the ErrorCode as a human-readable name.
func (e ErrorCode) String() string {
if s := errorCodeStrings[e]; s != "" {
return s
}
return fmt.Sprintf("Unknown ErrorCode (%d)", e)
}
// UnmarshalError describes a problem encountered while unmarshaling data.
// Some potential issues are unsupported Go types, attempting to decode a value
// which is too large to fit into a specified Go type, and exceeding max slice
// limitations.
type UnmarshalError struct {
ErrorCode ErrorCode // Describes the kind of error
Func string // Function name
Value interface{} // Value actually parsed where appropriate
Description string // Human readable description of the issue
Err error // The underlying error for IO errors
}
// Error satisfies the error interface and prints human-readable errors.
func (e *UnmarshalError) Error() string {
switch e.ErrorCode {
case ErrBadEnumValue, ErrOverflow, ErrIO, ErrParseTime:
return fmt.Sprintf("xdr:%s: %s - read: '%v'", e.Func,
e.Description, e.Value)
}
return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
}
// unmarshalError creates an error given a set of arguments and will copy byte
// slices into the Value field since they might otherwise be changed from from
// the original value.
func unmarshalError(f string, c ErrorCode, desc string, v interface{}, err error) *UnmarshalError {
e := &UnmarshalError{ErrorCode: c, Func: f, Description: desc, Err: err}
switch t := v.(type) {
case []byte:
slice := make([]byte, len(t))
copy(slice, t)
e.Value = slice
default:
e.Value = v
}
return e
}
// IsIO returns a boolean indicating whether the error is known to report that
// the underlying reader or writer encountered an ErrIO.
func IsIO(err error) bool {
switch e := err.(type) {
case *UnmarshalError:
return e.ErrorCode == ErrIO
case *MarshalError:
return e.ErrorCode == ErrIO
}
return false
}
// MarshalError describes a problem encountered while marshaling data.
// Some potential issues are unsupported Go types, attempting to encode more
// opaque data than can be represented by a single opaque XDR entry, and
// exceeding max slice limitations.
type MarshalError struct {
ErrorCode ErrorCode // Describes the kind of error
Func string // Function name
Value interface{} // Value actually parsed where appropriate
Description string // Human readable description of the issue
Err error // The underlying error for IO errors
}
// Error satisfies the error interface and prints human-readable errors.
func (e *MarshalError) Error() string {
switch e.ErrorCode {
case ErrIO:
return fmt.Sprintf("xdr:%s: %s - wrote: '%v'", e.Func,
e.Description, e.Value)
case ErrBadEnumValue:
return fmt.Sprintf("xdr:%s: %s - value: '%v'", e.Func,
e.Description, e.Value)
}
return fmt.Sprintf("xdr:%s: %s", e.Func, e.Description)
}
// marshalError creates an error given a set of arguments and will copy byte
// slices into the Value field since they might otherwise be changed from from
// the original value.
func marshalError(f string, c ErrorCode, desc string, v interface{}, err error) *MarshalError {
e := &MarshalError{ErrorCode: c, Func: f, Description: desc, Err: err}
switch t := v.(type) {
case []byte:
slice := make([]byte, len(t))
copy(slice, t)
e.Value = slice
default:
e.Value = v
}
return e
}

15538
vendor/github.com/digitalocean/go-libvirt/libvirt.gen.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

552
vendor/github.com/digitalocean/go-libvirt/libvirt.go generated vendored Normal file
View File

@ -0,0 +1,552 @@
// Copyright 2018 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.
// Package libvirt is a pure Go implementation of the libvirt RPC protocol.
// For more information on the protocol, see https://libvirt.org/internals/l.html
package libvirt
// We'll use c-for-go to extract the consts and typedefs from the libvirt
// sources so we don't have to duplicate them here.
//go:generate scripts/gen-consts.sh
import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"net"
"sync"
"github.com/digitalocean/go-libvirt/internal/constants"
xdr "github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2"
)
// ErrEventsNotSupported is returned by Events() if event streams
// are unsupported by either QEMU or libvirt.
var ErrEventsNotSupported = errors.New("event monitor is not supported")
// internal event
type event interface {
GetCallbackID() uint32
}
// Libvirt implements libvirt's remote procedure call protocol.
type Libvirt struct {
conn net.Conn
r *bufio.Reader
w *bufio.Writer
mu *sync.Mutex
// method callbacks
cm sync.Mutex
callbacks map[uint32]chan response
// event listeners
em sync.Mutex
events map[uint32]eventStream
// next request serial number
s uint32
}
// DomainEvent represents a libvirt domain event.
type DomainEvent struct {
CallbackID uint32
Domain Domain
Event string
Seconds uint64
Microseconds uint32
Padding uint8
Details []byte
}
// GetCallbackID returns the callback id of a qemu domain event
func (de DomainEvent) GetCallbackID() uint32 {
return de.CallbackID
}
// GetCallbackID returns the callback id of a libvirt lifecycle event
func (m DomainEventCallbackLifecycleMsg) GetCallbackID() uint32 {
return uint32(m.CallbackID)
}
// qemuError represents a QEMU process error.
type qemuError struct {
Error struct {
Class string `json:"class"`
Description string `json:"desc"`
} `json:"error"`
}
// Capabilities returns an XML document describing the host's capabilties.
func (l *Libvirt) Capabilities() ([]byte, error) {
caps, err := l.ConnectGetCapabilities()
return []byte(caps), err
}
// Connect establishes communication with the libvirt server.
// The underlying libvirt socket connection must be previously established.
func (l *Libvirt) Connect() error {
payload := struct {
Padding [3]byte
Name string
Flags uint32
}{
Padding: [3]byte{0x1, 0x0, 0x0},
Name: "qemu:///system",
Flags: 0,
}
buf, err := encode(&payload)
if err != nil {
return err
}
// libvirt requires that we call auth-list prior to connecting,
// event when no authentication is used.
_, err = l.request(constants.ProcAuthList, constants.Program, buf)
if err != nil {
return err
}
_, err = l.request(constants.ProcConnectOpen, constants.Program, buf)
if err != nil {
return err
}
return nil
}
// Disconnect shuts down communication with the libvirt server and closes the
// underlying net.Conn.
func (l *Libvirt) Disconnect() error {
// close event streams
for id := range l.events {
if err := l.removeStream(id); err != nil {
return err
}
}
// Deregister all the callbacks so that clients with outstanding requests
// will unblock.
l.deregisterAll()
_, err := l.request(constants.ProcConnectClose, constants.Program, nil)
if err != nil {
return err
}
return l.conn.Close()
}
// Domains returns a list of all domains managed by libvirt.
//
// Deprecated: use ConnectListAllDomains instead.
func (l *Libvirt) Domains() ([]Domain, error) {
// these are the flags as passed by `virsh` for `virsh list --all`
flags := ConnectListDomainsActive | ConnectListDomainsInactive
domains, _, err := l.ConnectListAllDomains(1, flags)
return domains, err
}
// DomainState returns state of the domain managed by libvirt.
//
// Deprecated: use DomainGetState instead.
func (l *Libvirt) DomainState(dom string) (DomainState, error) {
d, err := l.lookup(dom)
if err != nil {
return DomainNostate, err
}
state, _, err := l.DomainGetState(d, 0)
return DomainState(state), err
}
// Events streams domain events.
// If a problem is encountered setting up the event monitor connection
// an error will be returned. Errors encountered during streaming will
// cause the returned event channel to be closed.
func (l *Libvirt) Events(dom string) (<-chan DomainEvent, error) {
d, err := l.lookup(dom)
if err != nil {
return nil, err
}
payload := struct {
Padding [4]byte
Domain Domain
Event [2]byte
Flags [2]byte
}{
Padding: [4]byte{0x0, 0x0, 0x1, 0x0},
Domain: d,
Event: [2]byte{0x0, 0x0},
Flags: [2]byte{0x0, 0x0},
}
buf, err := encode(&payload)
if err != nil {
return nil, err
}
res, err := l.request(constants.QEMUConnectDomainMonitorEventRegister, constants.ProgramQEMU, buf)
if err != nil {
if err == ErrUnsupported {
return nil, ErrEventsNotSupported
}
return nil, err
}
dec := xdr.NewDecoder(bytes.NewReader(res.Payload))
cbID, _, err := dec.DecodeUint()
if err != nil {
return nil, err
}
stream := newEventStream(constants.QEMUConnectDomainMonitorEventDeregister, constants.ProgramQEMU)
l.addStream(cbID, stream)
c := make(chan DomainEvent)
go func() {
// process events
for e := range stream.Events {
c <- *e.(*DomainEvent)
}
}()
return c, nil
}
// LifecycleEvents streams lifecycle events.
// If a problem is encountered setting up the event monitor connection
// an error will be returned. Errors encountered during streaming will
// cause the returned event channel to be closed.
func (l *Libvirt) LifecycleEvents() (<-chan DomainEventLifecycleMsg, error) {
callbackID, err := l.ConnectDomainEventCallbackRegisterAny(int32(DomainEventIDLifecycle), nil)
if err != nil {
return nil, err
}
stream := newEventStream(constants.ProcConnectDomainEventCallbackDeregisterAny, constants.Program)
l.addStream(uint32(callbackID), stream)
c := make(chan DomainEventLifecycleMsg)
go func() {
// process events
for e := range stream.Events {
c <- e.(*DomainEventCallbackLifecycleMsg).Msg
}
}()
return c, nil
}
// Run executes the given QAPI command against a domain's QEMU instance.
// For a list of available QAPI commands, see:
// http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD
func (l *Libvirt) Run(dom string, cmd []byte) ([]byte, error) {
d, err := l.lookup(dom)
if err != nil {
return nil, err
}
payload := struct {
Domain Domain
Command []byte
Flags uint32
}{
Domain: d,
Command: cmd,
Flags: 0,
}
buf, err := encode(&payload)
if err != nil {
return nil, err
}
res, err := l.request(constants.QEMUDomainMonitor, constants.ProgramQEMU, buf)
if err != nil {
return nil, err
}
// check for QEMU process errors
if err = getQEMUError(res); err != nil {
return nil, err
}
r := bytes.NewReader(res.Payload)
dec := xdr.NewDecoder(r)
data, _, err := dec.DecodeFixedOpaque(int32(r.Len()))
if err != nil {
return nil, err
}
// drop QMP control characters from start of line, and drop
// any trailing NULL characters from the end
return bytes.TrimRight(data[4:], "\x00"), nil
}
// Secrets returns all secrets managed by the libvirt daemon.
//
// Deprecated: use ConnectListAllSecrets instead.
func (l *Libvirt) Secrets() ([]Secret, error) {
secrets, _, err := l.ConnectListAllSecrets(1, 0)
return secrets, err
}
// StoragePool returns the storage pool associated with the provided name.
// An error is returned if the requested storage pool is not found.
//
// Deprecated: use StoragePoolLookupByName instead.
func (l *Libvirt) StoragePool(name string) (StoragePool, error) {
return l.StoragePoolLookupByName(name)
}
// StoragePools returns a list of defined storage pools. Pools are filtered by
// the provided flags. See StoragePools*.
//
// Deprecated: use ConnectListAllStoragePools instead.
func (l *Libvirt) StoragePools(flags ConnectListAllStoragePoolsFlags) ([]StoragePool, error) {
pools, _, err := l.ConnectListAllStoragePools(1, flags)
return pools, err
}
// Undefine undefines the domain specified by dom, e.g., 'prod-lb-01'.
// The flags argument allows additional options to be specified such as
// cleaning up snapshot metadata. For more information on available
// flags, see DomainUndefine*.
//
// Deprecated: use DomainUndefineFlags instead.
func (l *Libvirt) Undefine(dom string, flags DomainUndefineFlagsValues) error {
d, err := l.lookup(dom)
if err != nil {
return err
}
return l.DomainUndefineFlags(d, flags)
}
// Destroy destroys the domain specified by dom, e.g., 'prod-lb-01'.
// The flags argument allows additional options to be specified such as
// allowing a graceful shutdown with SIGTERM than SIGKILL.
// For more information on available flags, see DomainDestroy*.
//
// Deprecated: use DomainDestroyFlags instead.
func (l *Libvirt) Destroy(dom string, flags DomainDestroyFlagsValues) error {
d, err := l.lookup(dom)
if err != nil {
return err
}
return l.DomainDestroyFlags(d, flags)
}
// XML returns a domain's raw XML definition, akin to `virsh dumpxml <domain>`.
// See DomainXMLFlag* for optional flags.
//
// Deprecated: use DomainGetXMLDesc instead.
func (l *Libvirt) XML(dom string, flags DomainXMLFlags) ([]byte, error) {
d, err := l.lookup(dom)
if err != nil {
return nil, err
}
xml, err := l.DomainGetXMLDesc(d, flags)
return []byte(xml), err
}
// DefineXML defines a domain, but does not start it.
//
// Deprecated: use DomainDefineXMLFlags instead.
func (l *Libvirt) DefineXML(x []byte, flags DomainDefineFlags) error {
_, err := l.DomainDefineXMLFlags(string(x), flags)
return err
}
// Version returns the version of the libvirt daemon.
//
// Deprecated: use ConnectGetLibVersion instead.
func (l *Libvirt) Version() (string, error) {
ver, err := l.ConnectGetLibVersion()
if err != nil {
return "", err
}
// The version is provided as an int following this formula:
// version * 1,000,000 + minor * 1000 + micro
// See src/libvirt-host.c # virConnectGetLibVersion
major := ver / 1000000
ver %= 1000000
minor := ver / 1000
ver %= 1000
micro := ver
versionString := fmt.Sprintf("%d.%d.%d", major, minor, micro)
return versionString, nil
}
// Shutdown shuts down a domain. Note that the guest OS may ignore the request.
// If flags is set to 0 then the hypervisor will choose the method of shutdown it considers best.
//
// Deprecated: use DomainShutdownFlags instead.
func (l *Libvirt) Shutdown(dom string, flags DomainShutdownFlagValues) error {
d, err := l.lookup(dom)
if err != nil {
return err
}
return l.DomainShutdownFlags(d, flags)
}
// Reboot reboots the domain. Note that the guest OS may ignore the request.
// If flags is set to zero, then the hypervisor will choose the method of shutdown it considers best.
//
// Deprecated: use DomainReboot instead.
func (l *Libvirt) Reboot(dom string, flags DomainRebootFlagValues) error {
d, err := l.lookup(dom)
if err != nil {
return err
}
return l.DomainReboot(d, flags)
}
// Reset resets domain immediately without any guest OS shutdown
//
// Deprecated: use DomainReset instead.
func (l *Libvirt) Reset(dom string) error {
d, err := l.lookup(dom)
if err != nil {
return err
}
return l.DomainReset(d, 0)
}
// BlockLimit contains a name and value pair for a Get/SetBlockIOTune limit. The
// Name field is the name of the limit (to see a list of the limits that can be
// applied, execute the 'blkdeviotune' command on a VM in virsh). Callers can
// use the QEMUBlockIO... constants below for the Name value. The Value field is
// the limit to apply.
type BlockLimit struct {
Name string
Value uint64
}
// SetBlockIOTune changes the per-device block I/O tunables within a guest.
// Parameters are the name of the VM, the name of the disk device to which the
// limits should be applied, and 1 or more BlockLimit structs containing the
// actual limits.
//
// The limits which can be applied here are enumerated in the QEMUBlockIO...
// constants above, and you can also see the full list by executing the
// 'blkdeviotune' command on a VM in virsh.
//
// Example usage:
// SetBlockIOTune("vm-name", "vda", BlockLimit{libvirt.QEMUBlockIOWriteBytesSec, 1000000})
//
// Deprecated: use DomainSetBlockIOTune instead.
func (l *Libvirt) SetBlockIOTune(dom string, disk string, limits ...BlockLimit) error {
d, err := l.lookup(dom)
if err != nil {
return err
}
params := make([]TypedParam, len(limits))
for ix, limit := range limits {
tpval := NewTypedParamValueUllong(limit.Value)
params[ix] = TypedParam{Field: limit.Name, Value: *tpval}
}
return l.DomainSetBlockIOTune(d, disk, params, uint32(DomainAffectLive))
}
// GetBlockIOTune returns a slice containing the current block I/O tunables for
// a disk.
//
// Deprecated: use DomainGetBlockIOTune instead.
func (l *Libvirt) GetBlockIOTune(dom string, disk string) ([]BlockLimit, error) {
d, err := l.lookup(dom)
if err != nil {
return nil, err
}
lims, _, err := l.DomainGetBlockIOTune(d, []string{disk}, 32, uint32(TypedParamStringOkay))
if err != nil {
return nil, err
}
var limits []BlockLimit
// now decode each of the returned TypedParams. To do this we read the field
// name and type, then use the type information to decode the value.
for _, lim := range lims {
var l BlockLimit
name := lim.Field
switch lim.Value.I.(type) {
case uint64:
l = BlockLimit{Name: name, Value: lim.Value.I.(uint64)}
}
limits = append(limits, l)
}
return limits, nil
}
// lookup returns a domain as seen by libvirt.
func (l *Libvirt) lookup(name string) (Domain, error) {
return l.DomainLookupByName(name)
}
// getQEMUError checks the provided response for QEMU process errors.
// If an error is found, it is extracted an returned, otherwise nil.
func getQEMUError(r response) error {
pl := bytes.NewReader(r.Payload)
dec := xdr.NewDecoder(pl)
s, _, err := dec.DecodeString()
if err != nil {
return err
}
var e qemuError
if err = json.Unmarshal([]byte(s), &e); err != nil {
return err
}
if e.Error.Description != "" {
return errors.New(e.Error.Description)
}
return nil
}
// New configures a new Libvirt RPC connection.
func New(conn net.Conn) *Libvirt {
l := &Libvirt{
conn: conn,
s: 0,
r: bufio.NewReader(conn),
w: bufio.NewWriter(conn),
mu: &sync.Mutex{},
callbacks: make(map[uint32]chan response),
events: make(map[uint32]eventStream),
}
go l.listen()
return l
}

64
vendor/github.com/digitalocean/go-libvirt/libvirt.yml generated vendored Normal file
View File

@ -0,0 +1,64 @@
# Configuration file for c-for-go, which go-libvirt uses to translate the const
# and type definitions from the C-language sources in the libvirt project into
# Go. This file is used by the c-for-go binary (github.com/xlab/c-for-go), which
# is called when 'go generate' is run. See libvirt.go for the command line used.
---
GENERATOR:
PackageName: libvirt
PackageLicense: |
Copyright 2018 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.
Includes: []
PARSER:
# We can't use environment variables here, but we don't want to process the
# libvirt version installed in the system folders (if any). Instead we'll
# rely on our caller to link the libvirt source directory to lv_source/, and
# run on that code. This isn't ideal, but changes to c-for-go are needed to
# fix it.
IncludePaths: [./lv_source/include]
SourcesPaths:
- libvirt/libvirt.h
- libvirt/virterror.h
TRANSLATOR:
ConstRules:
defines: eval
Rules:
global:
- {action: accept, from: "^vir"}
post-global:
- {action: replace, from: "^vir"}
- {load: snakecase}
# Follow golint's capitalization conventions.
- {action: replace, from: "Api([A-Z]|$)", to: "API$1"}
- {action: replace, from: "Cpu([A-Z]|$)", to: "CPU$1"}
- {action: replace, from: "Dns([A-Z]|$)", to: "DNS$1"}
- {action: replace, from: "Eof([A-Z]|$)", to: "EOF$1"}
- {action: replace, from: "Id([A-Z]|$)", to: "ID$1"}
- {action: replace, from: "Ip([A-Z]|$)", to: "IP$1"}
- {action: replace, from: "Tls([A-Z]|$)", to: "TLS$1"}
- {action: replace, from: "Uuid([A-Z]|$)", to: "UUID$1"}
- {action: replace, from: "Uri([A-Z]|$)", to: "URI$1"}
- {action: replace, from: "Vcpu([A-Z]|$)", to: "VCPU$1"}
- {action: replace, from: "Xml([A-Z]|$)", to: "XML$1"}
- {action: replace, from: "Rpc([A-Z]|$)", to: "RPC$1"}
- {action: replace, from: "Ssh([A-Z]|$)", to: "SSH$1"}
- {action: replace, from: "Http([A-Z]|$)", to: "HTTP$1"}
- {transform: unexport, from: "^(Err|From|War)"}
const:
- {action: accept, from: "^VIR_"}
# Special case to prevent a collision with a type:
- {action: replace, from: "^VIR_DOMAIN_JOB_OPERATION", to: "VIR_DOMAIN_JOB_OPERATION_STR"}
- {transform: lower}

View File

@ -0,0 +1,7 @@
# libvirtd configuration for travis-ci
listen_tls = 0
listen_tcp = 1
tcp_port = "16509"
listen_addr = "127.0.0.1"
auth_unix_rw = "none"
auth_tcp = "none"

557
vendor/github.com/digitalocean/go-libvirt/rpc.go generated vendored Normal file
View File

@ -0,0 +1,557 @@
// Copyright 2018 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.
package libvirt
import (
"bytes"
"encoding/binary"
"errors"
"io"
"strings"
"sync/atomic"
"github.com/digitalocean/go-libvirt/internal/constants"
xdr "github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2"
)
// ErrUnsupported is returned if a procedure is not supported by libvirt
var ErrUnsupported = errors.New("unsupported procedure requested")
// request and response types
const (
// Call is used when making calls to the remote server.
Call = iota
// Reply indicates a server reply.
Reply
// Message is an asynchronous notification.
Message
// Stream represents a stream data packet.
Stream
// CallWithFDs is used by a client to indicate the request has
// arguments with file descriptors.
CallWithFDs
// ReplyWithFDs is used by a server to indicate the request has
// arguments with file descriptors.
ReplyWithFDs
)
// request and response statuses
const (
// StatusOK is always set for method calls or events.
// For replies it indicates successful completion of the method.
// For streams it indicates confirmation of the end of file on the stream.
StatusOK = iota
// StatusError for replies indicates that the method call failed
// and error information is being returned. For streams this indicates
// that not all data was sent and the stream has aborted.
StatusError
// StatusContinue is only used for streams.
// This indicates that further data packets will be following.
StatusContinue
)
// header is a libvirt rpc packet header
type header struct {
// Program identifier
Program uint32
// Program version
Version uint32
// Remote procedure identifier
Procedure uint32
// Call type, e.g., Reply
Type uint32
// Call serial number
Serial uint32
// Request status, e.g., StatusOK
Status uint32
}
// packet represents a RPC request or response.
type packet struct {
// Size of packet, in bytes, including length.
// Len + Header + Payload
Len uint32
Header header
}
// internal rpc response
type response struct {
Payload []byte
Status uint32
}
// event stream associated with a program and a procedure
type eventStream struct {
// Channel of events sent by libvirt
Events chan event
// Remote procedure identifier used to unregister callback
DeregisterProc uint32
// Program identifier
Program uint32
}
// helper to create an event stream
func newEventStream(deregisterProc, program uint32) eventStream {
return eventStream{Events: make(chan event), DeregisterProc: deregisterProc, Program: program}
}
// libvirt error response
type libvirtError struct {
Code uint32
DomainID uint32
Padding uint8
Message string
Level uint32
}
func (e libvirtError) Error() string {
return e.Message
}
// checkError is used to check whether an error is a libvirtError, and if it is,
// whether its error code matches the one passed in. It will return false if
// these conditions are not met.
func checkError(err error, expectedError errorNumber) bool {
e, ok := err.(libvirtError)
if ok {
return e.Code == uint32(expectedError)
}
return false
}
// IsNotFound detects libvirt's ERR_NO_DOMAIN.
func IsNotFound(err error) bool {
return checkError(err, errNoDomain)
}
// listen processes incoming data and routes
// responses to their respective callback handler.
func (l *Libvirt) listen() {
for {
// response packet length
length, err := pktlen(l.r)
if err != nil {
// When the underlying connection EOFs or is closed, stop
// this goroutine
if err == io.EOF || strings.Contains(err.Error(), "use of closed network connection") {
return
}
// invalid packet
continue
}
// response header
h, err := extractHeader(l.r)
if err != nil {
// invalid packet
continue
}
// payload: packet length minus what was previously read
size := int(length) - (constants.PacketLengthSize + constants.HeaderSize)
buf := make([]byte, size)
_, err = io.ReadFull(l.r, buf)
if err != nil {
// invalid packet
continue
}
// route response to caller
l.route(h, buf)
}
}
// callback sends rpc responses to their respective caller.
func (l *Libvirt) callback(id uint32, res response) {
l.cm.Lock()
c, ok := l.callbacks[id]
l.cm.Unlock()
if ok {
// we close the channel in deregister() so that we don't block here
// forever without a receiver. If that happens, this write will panic.
defer func() {
recover()
}()
c <- res
}
}
// route sends incoming packets to their listeners.
func (l *Libvirt) route(h *header, buf []byte) {
// route events to their respective listener
var streamEvent event
switch {
case h.Program == constants.ProgramQEMU && h.Procedure == constants.QEMUDomainMonitorEvent:
streamEvent = &DomainEvent{}
case h.Program == constants.Program && h.Procedure == constants.ProcDomainEventCallbackLifecycle:
streamEvent = &DomainEventCallbackLifecycleMsg{}
}
if streamEvent != nil {
err := eventDecoder(buf, streamEvent)
if err != nil { // event was malformed, drop.
return
}
l.stream(streamEvent)
return
}
// send responses to caller
res := response{
Payload: buf,
Status: h.Status,
}
l.callback(h.Serial, res)
}
// serial provides atomic access to the next sequential request serial number.
func (l *Libvirt) serial() uint32 {
return atomic.AddUint32(&l.s, 1)
}
// stream decodes domain events and sends them
// to the respective event listener.
func (l *Libvirt) stream(e event) error {
// send to event listener
l.em.Lock()
c, ok := l.events[e.GetCallbackID()]
l.em.Unlock()
if ok {
// we close the channel in deregister() so that we don't block here
// forever without a receiver. If that happens, this write will panic.
defer func() {
recover()
}()
c.Events <- e
}
return nil
}
// addStream configures the routing for an event stream.
func (l *Libvirt) addStream(id uint32, s eventStream) {
l.em.Lock()
l.events[id] = s
l.em.Unlock()
}
// removeStream notifies the libvirt server to stop sending events
// for the provided callback id. Upon successful de-registration the
// callback handler is destroyed.
func (l *Libvirt) removeStream(id uint32) error {
stream := l.events[id]
close(stream.Events)
payload := struct {
CallbackID uint32
}{
CallbackID: id,
}
buf, err := encode(&payload)
if err != nil {
return err
}
_, err = l.request(stream.DeregisterProc, stream.Program, buf)
if err != nil {
return err
}
l.em.Lock()
delete(l.events, id)
l.em.Unlock()
return nil
}
// register configures a method response callback
func (l *Libvirt) register(id uint32, c chan response) {
l.cm.Lock()
l.callbacks[id] = c
l.cm.Unlock()
}
// deregister destroys a method response callback
func (l *Libvirt) deregister(id uint32) {
l.cm.Lock()
if _, ok := l.callbacks[id]; ok {
close(l.callbacks[id])
delete(l.callbacks, id)
}
l.cm.Unlock()
}
// deregisterAll closes all the waiting callback channels. This is used to clean
// up if the connection to libvirt is lost. Callers waiting for responses will
// return an error when the response channel is closed, rather than just
// hanging.
func (l *Libvirt) deregisterAll() {
l.cm.Lock()
for id := range l.callbacks {
// can't call deregister() here because we're already holding the lock.
close(l.callbacks[id])
delete(l.callbacks, id)
}
l.cm.Unlock()
}
// request performs a libvirt RPC request.
// 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
}
}
}
}
// requestStream performs a libvirt RPC request. The outStream and inStream
// parameters are optional, and should be nil for RPC endpoints that don't
// return a stream.
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 n > 0 {
err2 := l.sendPacket(serial, proc, program, buf[:n], Stream, StatusContinue)
if err2 != nil {
return err2
}
}
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
}
}
}
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)
}
p := packet{
Len: uint32(size),
Header: header{
Program: program,
Version: constants.ProtocolVersion,
Procedure: proc,
Type: typ,
Serial: serial,
Status: status,
},
}
// write header
l.mu.Lock()
defer l.mu.Unlock()
err := binary.Write(l.w, binary.BigEndian, p)
if err != nil {
return err
}
// write payload
if payload != nil {
err = binary.Write(l.w, binary.BigEndian, payload)
if err != nil {
return err
}
}
return l.w.Flush()
}
func (l *Libvirt) getResponse(c chan response) (response, error) {
resp := <-c
if resp.Status == StatusError {
return resp, decodeError(resp.Payload)
}
return resp, nil
}
// encode XDR encodes the provided data.
func encode(data interface{}) ([]byte, error) {
var buf bytes.Buffer
_, err := xdr.Marshal(&buf, data)
return buf.Bytes(), err
}
// decodeError extracts an error message from the provider buffer.
func decodeError(buf []byte) error {
var e libvirtError
dec := xdr.NewDecoder(bytes.NewReader(buf))
_, err := dec.Decode(&e)
if err != nil {
return err
}
if strings.Contains(e.Message, "unknown procedure") {
return ErrUnsupported
}
// if libvirt returns ERR_OK, ignore the error
if checkError(e, errOk) {
return nil
}
return e
}
// eventDecoder decoder an event from a xdr buffer.
func eventDecoder(buf []byte, e interface{}) error {
dec := xdr.NewDecoder(bytes.NewReader(buf))
_, err := dec.Decode(e)
return err
}
// pktlen determines the length of an incoming rpc response.
// If an error is encountered reading the provided Reader, the
// error is returned and response length will be 0.
func pktlen(r io.Reader) (uint32, error) {
buf := make([]byte, constants.PacketLengthSize)
for n := 0; n < cap(buf); {
nn, err := r.Read(buf)
if err != nil {
return 0, err
}
n += nn
}
return binary.BigEndian.Uint32(buf), nil
}
// extractHeader returns the decoded header from an incoming response.
func extractHeader(r io.Reader) (*header, error) {
buf := make([]byte, constants.HeaderSize)
for n := 0; n < cap(buf); {
nn, err := r.Read(buf)
if err != nil {
return nil, err
}
n += nn
}
h := &header{
Program: binary.BigEndian.Uint32(buf[0:4]),
Version: binary.BigEndian.Uint32(buf[4:8]),
Procedure: binary.BigEndian.Uint32(buf[8:12]),
Type: binary.BigEndian.Uint32(buf[12:16]),
Serial: binary.BigEndian.Uint32(buf[16:20]),
Status: binary.BigEndian.Uint32(buf[20:24]),
}
return h, nil
}

27
vendor/github.com/digitalocean/go-libvirt/units.go generated vendored 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
)

17
vendor/github.com/digitalocean/go-qemu/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,17 @@
Maintainer
----------
DigitalOcean, Inc
Original Authors
----------------
Ben LeMasurier <blemasurier@digitalocean.com>
Matt Layher <mlayher@digitalocean.com>
Contributors
------------
David Anderson <dave@natulte.net>
Justin Kim <justin@digitalocean.com>
Luis Sagastume <lsagastume1990@gmail.com>
Nedim Dedic <nedim_dedic@yahoo.com>
Roberto J Rojas <robertojrojas@gmail.com>
Marko Mudrinic <mudrinic.mare@gmail.com>

195
vendor/github.com/digitalocean/go-qemu/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,195 @@
Apache License
==============
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
### Terms and Conditions for use, reproduction, and distribution
#### 1. Definitions
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
#### 2. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
#### 3. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
#### 4. Redistribution
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
#### 5. Submission of Contributions
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
#### 6. Trademarks
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
#### 7. Disclaimer of Warranty
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
#### 8. Limitation of Liability
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
#### 9. Accepting Warranty or Additional Liability
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
_END OF TERMS AND CONDITIONS_
### APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets `[]` replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same “printed page” as the copyright notice for easier identification within
third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

104
vendor/github.com/digitalocean/go-qemu/qmp/README.md generated vendored Normal file
View File

@ -0,0 +1,104 @@
QMP
===
Package `qmp` enables interaction with QEMU instances via the QEMU Machine Protocol (QMP).
## Available Drivers
### Libvirt
If your environment is managed by Libvirt, QMP interaction must be proxied through the Libvirt daemon. This can be be done through two available drivers:
#### RPC
The RPC driver provides a pure Go implementation of Libvirt's RPC protocol.
```go
//conn, err := net.DialTimeout("unix", "/var/run/libvirt/libvirt-sock", 2*time.Second)
conn, err := net.DialTimeout("tcp", "192.168.1.1:16509", 2*time.Second)
monitor := libvirtrpc.New("stage-lb-1", conn)
```
#### virsh
A connection to the monitor socket is provided by proxing requests through the `virsh` executable.
```go
monitor, err := qmp.NewLibvirtMonitor("qemu:///system", "stage-lb-1")
```
### Socket
If your QEMU instances are not managed by libvirt, direct communication over its UNIX socket is available.
```go
monitor, err := qmp.NewSocketMonitor("unix", "/var/lib/qemu/example.monitor", 2*time.Second)
```
## Examples
Using the above to establish a new `qmp.Monitor`, the following examples provide a brief overview of QMP usage.
_error checking omitted for the sake of brevity._
### Command Execution
```go
type StatusResult struct {
ID string `json:"id"`
Return struct {
Running bool `json:"running"`
Singlestep bool `json:"singlestep"`
Status string `json:"status"`
} `json:"return"`
}
monitor.Connect()
defer monitor.Disconnect()
cmd := []byte(`{ "execute": "query-status" }`)
raw, _ := monitor.Run(cmd)
var result StatusResult
json.Unmarshal(raw, &result)
fmt.Println(result.Return.Status)
```
```
running
```
### Event Monitor
```go
monitor.Connect()
defer monitor.Disconnect()
stream, _ := monitor.Events()
for e := range stream {
log.Printf("EVENT: %s", e.Event)
}
```
```
$ virsh reboot example
Domain example is being rebooted
```
```
EVENT: POWERDOWN
EVENT: SHUTDOWN
EVENT: STOP
EVENT: RESET
EVENT: RESUME
EVENT: RESET
...
```
## More information
* [QEMU QMP Wiki](http://wiki.qemu.org/QMP)
* [QEMU QMP Intro](http://git.qemu.org/?p=qemu.git;a=blob_plain;f=docs/qmp-intro.txt;hb=HEAD)
* [QEMU QMP Events](http://git.qemu.org/?p=qemu.git;a=blob_plain;f=docs/qmp-events.txt;hb=HEAD)
* [QEMU QMP Spec](http://git.qemu.org/?p=qemu.git;a=blob_plain;f=docs/qmp-spec.txt;hb=HEAD)

93
vendor/github.com/digitalocean/go-qemu/qmp/qmp.go generated vendored Normal file
View File

@ -0,0 +1,93 @@
// Copyright 2016 The go-qemu 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.
// Package qmp enables interaction with QEMU instances
// via the QEMU Machine Protocol (QMP).
package qmp
import (
"errors"
"fmt"
)
// ErrEventsNotSupported is returned by Events() if event streams
// are unsupported by either QEMU or libvirt.
var ErrEventsNotSupported = errors.New("event monitor is not supported")
// Monitor represents a QEMU Machine Protocol socket.
// See: http://wiki.qemu.org/QMP
type Monitor interface {
Connect() error
Disconnect() error
Run(command []byte) (out []byte, err error)
Events() (events <-chan Event, err error)
}
// Command represents a QMP command.
type Command struct {
// Name of the command to run
Execute string `json:"execute"`
// Optional arguments for the above command.
Args interface{} `json:"arguments,omitempty"`
}
type response struct {
ID string `json:"id"`
Return interface{} `json:"return,omitempty"`
Error struct {
Class string `json:"class"`
Desc string `json:"desc"`
} `json:"error,omitempty"`
}
func (r *response) Err() error {
if r.Error.Desc == "" {
return nil
}
return errors.New(r.Error.Desc)
}
// Event represents a QEMU QMP event.
// See http://wiki.qemu.org/QMP
type Event struct {
// Event name, e.g., BLOCK_JOB_COMPLETE
Event string `json:"event"`
// Arbitrary event data
Data map[string]interface{} `json:"data"`
// Event timestamp, provided by QEMU.
Timestamp struct {
Seconds int64 `json:"seconds"`
Microseconds int64 `json:"microseconds"`
} `json:"timestamp"`
}
// Version is the QEMU version structure returned when a QMP connection is
// initiated.
type Version struct {
Package string `json:"package"`
QEMU struct {
Major int `json:"major"`
Micro int `json:"micro"`
Minor int `json:"minor"`
} `json:"qemu"`
}
func (v Version) String() string {
q := v.QEMU
return fmt.Sprintf("%d.%d.%d", q.Major, q.Minor, q.Micro)
}

106
vendor/github.com/digitalocean/go-qemu/qmp/rpc.go generated vendored Normal file
View File

@ -0,0 +1,106 @@
// Copyright 2016 The go-qemu 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.
package qmp
import (
"encoding/json"
"net"
"github.com/digitalocean/go-libvirt"
)
var _ Monitor = &LibvirtRPCMonitor{}
// A LibvirtRPCMonitor implements LibVirt's remote procedure call protocol.
type LibvirtRPCMonitor struct {
l *libvirt.Libvirt
// Domain name as seen by libvirt, e.g., stage-lb-1
Domain string
}
// NewLibvirtRPCMonitor configures a new Libvirt RPC Monitor connection.
// The provided domain should be the name of the domain as seen
// by libvirt, e.g., stage-lb-1.
func NewLibvirtRPCMonitor(domain string, conn net.Conn) *LibvirtRPCMonitor {
l := libvirt.New(conn)
return &LibvirtRPCMonitor{
l: l,
Domain: domain,
}
}
// Connect establishes communication with the libvirt server.
// The underlying libvirt socket connection must be previously established.
func (rpc *LibvirtRPCMonitor) Connect() error {
return rpc.l.Connect()
}
// Disconnect shuts down communication with the libvirt server
// and closes the underlying net.Conn.
func (rpc *LibvirtRPCMonitor) Disconnect() error {
return rpc.l.Disconnect()
}
// Events streams QEMU QMP Events.
// If a problem is encountered setting up the event monitor connection
// an error will be returned. Errors encountered during streaming will
// cause the returned event channel to be closed.
func (rpc *LibvirtRPCMonitor) Events() (<-chan Event, error) {
events, err := rpc.l.Events(rpc.Domain)
if err != nil {
return nil, err
}
c := make(chan Event)
go func() {
// process events
for e := range events {
qe, err := qmpEvent(&e)
if err != nil {
close(c)
break
}
c <- *qe
}
}()
return c, nil
}
// Run executes the given QAPI command against a domain's QEMU instance.
// For a list of available QAPI commands, see:
// http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD
func (rpc *LibvirtRPCMonitor) Run(cmd []byte) ([]byte, error) {
return rpc.l.Run(rpc.Domain, cmd)
}
// qmpEvent takes a libvirt DomainEvent and returns the QMP equivalent.
func qmpEvent(e *libvirt.DomainEvent) (*Event, error) {
var qe Event
if e.Details != nil {
if err := json.Unmarshal(e.Details, &qe.Data); err != nil {
return nil, err
}
}
qe.Event = e.Event
qe.Timestamp.Seconds = int64(e.Seconds)
qe.Timestamp.Microseconds = int64(e.Microseconds)
return &qe, nil
}

234
vendor/github.com/digitalocean/go-qemu/qmp/socket.go generated vendored Normal file
View File

@ -0,0 +1,234 @@
// Copyright 2016 The go-qemu 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.
package qmp
import (
"bufio"
"encoding/json"
"io"
"net"
"sync"
"sync/atomic"
"time"
)
// A SocketMonitor is a Monitor which speaks directly to a QEMU Machine Protocol
// (QMP) socket. Communication is performed directly using a QEMU monitor socket,
// typically using a UNIX socket or TCP connection. Multiple connections to the
// same domain are not permitted, and will result in the monitor blocking until
// the existing connection is closed.
type SocketMonitor struct {
// QEMU version reported by a connected monitor socket.
Version *Version
// Underlying connection
c net.Conn
// Serialize running command against domain
mu sync.Mutex
// Send command responses and errors
stream <-chan streamResponse
// Send domain events to listeners when available
listeners *int32
events <-chan Event
}
// NewSocketMonitor configures a connection to the provided QEMU monitor socket.
// An error is returned if the socket cannot be successfully dialed, or the
// dial attempt times out.
//
// NewSocketMonitor may dial the QEMU socket using a variety of connection types:
// NewSocketMonitor("unix", "/var/lib/qemu/example.monitor", 2 * time.Second)
// NewSocketMonitor("tcp", "8.8.8.8:4444", 2 * time.Second)
func NewSocketMonitor(network, addr string, timeout time.Duration) (*SocketMonitor, error) {
c, err := net.DialTimeout(network, addr, timeout)
if err != nil {
return nil, err
}
mon := &SocketMonitor{
c: c,
listeners: new(int32),
}
return mon, nil
}
// Listen creates a new SocketMonitor listening for a single connection to the provided socket file or address.
// An error is returned if unable to listen at the specified file path or port.
//
// Listen will wait for a QEMU socket connection using a variety connection types:
// Listen("unix", "/var/lib/qemu/example.monitor")
// Listen("tcp", "0.0.0.0:4444")
func Listen(network, addr string) (*SocketMonitor, error) {
l, err := net.Listen(network, addr)
if err != nil {
return nil, err
}
c, err := l.Accept()
defer l.Close()
if err != nil {
return nil, err
}
mon := &SocketMonitor{
c: c,
listeners: new(int32),
}
return mon, nil
}
// Disconnect closes the QEMU monitor socket connection.
func (mon *SocketMonitor) Disconnect() error {
atomic.StoreInt32(mon.listeners, 0)
err := mon.c.Close()
return err
}
// qmpCapabilities is the command which must be executed to perform the
// QEMU QMP handshake.
const qmpCapabilities = "qmp_capabilities"
// Connect sets up a QEMU QMP connection by connecting directly to the QEMU
// monitor socket. An error is returned if the capabilities handshake does
// not succeed.
func (mon *SocketMonitor) Connect() error {
enc := json.NewEncoder(mon.c)
dec := json.NewDecoder(mon.c)
// Check for banner on startup
var ban banner
if err := dec.Decode(&ban); err != nil {
return err
}
mon.Version = &ban.QMP.Version
// Issue capabilities handshake
cmd := Command{Execute: qmpCapabilities}
if err := enc.Encode(cmd); err != nil {
return err
}
// Check for no error on return
var r response
if err := dec.Decode(&r); err != nil {
return err
}
if err := r.Err(); err != nil {
return err
}
// Initialize socket listener for command responses and asynchronous
// events
events := make(chan Event)
stream := make(chan streamResponse)
go mon.listen(mon.c, events, stream)
mon.events = events
mon.stream = stream
return nil
}
// Events streams QEMU QMP Events.
// Events should only be called once per Socket. If used with a qemu.Domain,
// qemu.Domain.Events should be called to retrieve events instead.
func (mon *SocketMonitor) Events() (<-chan Event, error) {
atomic.AddInt32(mon.listeners, 1)
return mon.events, nil
}
// listen listens for incoming data from a QEMU monitor socket. It determines
// if the data is an asynchronous event or a response to a command, and returns
// the data on the appropriate channel.
func (mon *SocketMonitor) listen(r io.Reader, events chan<- Event, stream chan<- streamResponse) {
defer close(events)
defer close(stream)
scanner := bufio.NewScanner(r)
for scanner.Scan() {
var e Event
b := scanner.Bytes()
if err := json.Unmarshal(b, &e); err != nil {
continue
}
// If data does not have an event type, it must be in response to a command.
if e.Event == "" {
stream <- streamResponse{buf: b}
continue
}
// If nobody is listening for events, do not bother sending them.
if atomic.LoadInt32(mon.listeners) == 0 {
continue
}
events <- e
}
if err := scanner.Err(); err != nil {
stream <- streamResponse{err: err}
}
}
// Run executes the given QAPI command against a domain's QEMU instance.
// For a list of available QAPI commands, see:
// http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD
func (mon *SocketMonitor) Run(command []byte) ([]byte, error) {
// Only allow a single command to be run at a time to ensure that responses
// to a command cannot be mixed with responses from another command
mon.mu.Lock()
defer mon.mu.Unlock()
if _, err := mon.c.Write(command); err != nil {
return nil, err
}
// Wait for a response or error to our command
res := <-mon.stream
if res.err != nil {
return nil, res.err
}
// Check for QEMU errors
var r response
if err := json.Unmarshal(res.buf, &r); err != nil {
return nil, err
}
if err := r.Err(); err != nil {
return nil, err
}
return res.buf, nil
}
// banner is a wrapper type around a Version.
type banner struct {
QMP struct {
Version Version `json:"version"`
} `json:"QMP"`
}
// streamResponse is a struct sent over a channel in response to a command.
type streamResponse struct {
buf []byte
err error
}

6
vendor/modules.txt vendored
View File

@ -149,6 +149,12 @@ github.com/creack/goselect
github.com/davecgh/go-spew/spew
# github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dgrijalva/jwt-go
# github.com/digitalocean/go-libvirt v0.0.0-20190626172931-4d226dd6c437
github.com/digitalocean/go-libvirt
github.com/digitalocean/go-libvirt/internal/constants
github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2
# github.com/digitalocean/go-qemu v0.0.0-20181112162955-dd7bb9c771b8
github.com/digitalocean/go-qemu/qmp
# github.com/digitalocean/godo v1.11.1
github.com/digitalocean/godo
# github.com/docker/docker v0.0.0-20180422163414-57142e89befe

View File

@ -282,6 +282,9 @@ Linux server and have not enabled X11 forwarding (`ssh -X`).
switch/value pairs. Any value specified as an empty string is ignored. All
values after the switch are concatenated with no separator.
- `qmp_socket_path` (string) - QMP Socket Path when `vnc_use_password` is true.
Defaults to `output_directory`/`vm_name`.monitor.
~&gt; **Warning:** The qemu command line allows extreme flexibility, so beware
of conflicting arguments causing failures of your run. For instance, using
--no-acpi could break the ability to send power signal type commands (e.g.,
@ -390,6 +393,10 @@ default port of `5985` or whatever value you have the service set to listen on.
Packer uses a randomly chosen port in this range that appears available. By
default this is `5900` to `6000`. The minimum and maximum ports are inclusive.
- `vnc_use_password` (bool) - Whether or not to set a password on the VNC server.
This option automatically enables the QMP socket. See `qmp_socket_path`.
Defaults to `false`.
## Boot Command
The `boot_command` configuration is very important: it specifies the keys to