Merge pull request #7836 from 70k10/vncpassword
QEMU builder - implement VNC password functionality
This commit is contained in:
commit
2d02ea209d
|
@ -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{},
|
||||
)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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" +
|
||||
|
|
|
@ -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
2
go.mod
|
@ -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
4
go.sum
|
@ -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=
|
||||
|
|
|
@ -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 ./...
|
|
@ -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>
|
|
@ -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.
|
|
@ -0,0 +1,195 @@
|
|||
Apache License
|
||||
==============
|
||||
|
||||
_Version 2.0, January 2004_
|
||||
_<<http://www.apache.org/licenses/>>_
|
||||
|
||||
### 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.
|
||||
|
|
@ -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
|
||||
```
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
992
vendor/github.com/digitalocean/go-libvirt/internal/constants/constants.gen.go
generated
vendored
Normal file
992
vendor/github.com/digitalocean/go-libvirt/internal/constants/constants.gen.go
generated
vendored
Normal 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
|
||||
)
|
|
@ -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.
|
896
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/decode.go
generated
vendored
Normal file
896
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/decode.go
generated
vendored
Normal 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}
|
||||
}
|
171
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/doc.go
generated
vendored
Normal file
171
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/doc.go
generated
vendored
Normal 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
|
669
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/encode.go
generated
vendored
Normal file
669
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/encode.go
generated
vendored
Normal 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}
|
||||
}
|
177
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/error.go
generated
vendored
Normal file
177
vendor/github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2/error.go
generated
vendored
Normal 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
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
}
|
|
@ -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}
|
|
@ -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"
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
)
|
|
@ -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>
|
|
@ -0,0 +1,195 @@
|
|||
Apache License
|
||||
==============
|
||||
|
||||
_Version 2.0, January 2004_
|
||||
_<<http://www.apache.org/licenses/>>_
|
||||
|
||||
### 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.
|
||||
|
|
@ -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)
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
~> **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
|
||||
|
|
Loading…
Reference in New Issue