mirror of
https://github.com/containers/podman.git
synced 2025-06-24 11:28:24 +08:00
fix(deps): update github.com/digitalocean/go-qemu digest to f035778
Signed-off-by: Renovate Bot <bot@renovateapp.com>
This commit is contained in:
4
go.mod
4
go.mod
@ -23,7 +23,7 @@ require (
|
||||
github.com/coreos/go-systemd/v22 v22.5.0
|
||||
github.com/coreos/stream-metadata-go v0.4.1
|
||||
github.com/cyphar/filepath-securejoin v0.2.3
|
||||
github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001
|
||||
github.com/digitalocean/go-qemu v0.0.0-20221209210016-f035778c97f7
|
||||
github.com/docker/docker v23.0.5+incompatible
|
||||
github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11
|
||||
github.com/docker/go-plugins-helpers v0.0.0-20211224144127-6eecb7beb651
|
||||
@ -87,7 +87,7 @@ require (
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20201209184759-e2a69bcd5bd1 // indirect
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e // indirect
|
||||
github.com/disiqueira/gotree/v3 v3.0.2 // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||
|
13
go.sum
13
go.sum
@ -303,10 +303,10 @@ github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8l
|
||||
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20201209184759-e2a69bcd5bd1 h1:j6vGflaQ2T7yOWqVgPdiRF73j/U2Zmpbbzab8nyDCRQ=
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20201209184759-e2a69bcd5bd1/go.mod h1:QS1XzqZLcDniNYrN7EZefq3wIyb/M2WmJbql4ZKoc1Q=
|
||||
github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001 h1:WAg57gnaAWWjMAELcwHjc2xy0PoXQ5G+vn3+XS6s1jI=
|
||||
github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001/go.mod h1:IetBE52JfFxK46p2n2Rqm+p5Gx1gpu2hRHsrbnPOWZQ=
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e h1:SCnqm8SjSa0QqRxXbo5YY//S+OryeJioe17nK+iDZpg=
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e/go.mod h1:o129ljs6alsIQTc8d6eweihqpmmrbxZ2g1jhgjhPykI=
|
||||
github.com/digitalocean/go-qemu v0.0.0-20221209210016-f035778c97f7 h1:3OVJAbR131SnAXao7c9w8bFlAGH0oa29DCwsa88MJGk=
|
||||
github.com/digitalocean/go-qemu v0.0.0-20221209210016-f035778c97f7/go.mod h1:K4+o74YGNjOb9N6yyG+LPj1NjHtk+Qz0IYQPvirbaLs=
|
||||
github.com/disiqueira/gotree/v3 v3.0.2 h1:ik5iuLQQoufZBNPY518dXhiO5056hyNBIK9lWhkNRq8=
|
||||
github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8=
|
||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
@ -352,7 +352,6 @@ github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi
|
||||
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw=
|
||||
github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 h1:IeaD1VDVBPlx3viJT9Md8if8IxxJnO+x0JCGb054heg=
|
||||
github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52 h1:a4DFiKFJiDRGFD1qIcqGLX/WlUMD9dyLSLDt+9QZgt8=
|
||||
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
@ -1019,7 +1018,6 @@ github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
|
||||
github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE=
|
||||
github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
@ -1146,7 +1144,6 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
@ -1252,7 +1249,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -1345,7 +1341,6 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
|
||||
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
|
1
vendor/github.com/digitalocean/go-libvirt/.gitignore
generated
vendored
Normal file
1
vendor/github.com/digitalocean/go-libvirt/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
.idea/
|
62
vendor/github.com/digitalocean/go-libvirt/.travis.yml
generated
vendored
62
vendor/github.com/digitalocean/go-libvirt/.travis.yml
generated
vendored
@ -1,62 +0,0 @@
|
||||
language: go
|
||||
os: linux
|
||||
dist: bionic
|
||||
sudo: require
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.ccache
|
||||
|
||||
go:
|
||||
- "1.15"
|
||||
|
||||
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 ./...
|
6
vendor/github.com/digitalocean/go-libvirt/AUTHORS
generated
vendored
6
vendor/github.com/digitalocean/go-libvirt/AUTHORS
generated
vendored
@ -21,4 +21,8 @@ Yuriy Taraday <yorik.sar@gmail.com>
|
||||
Sylvain Baubeau <sbaubeau@redhat.com>
|
||||
David Schneider <dsbrng25b@gmail.com>
|
||||
Alec Hothan <ahothan@gmail.com>
|
||||
Akos Varga <vrgakos@gmail.com>
|
||||
Akos Varga <vrgakos@gmail.com>
|
||||
Peter Kurfer <peter.kurfer@gmail.com>
|
||||
Sam Roberts <sroberts@digitalocean.com>
|
||||
Moritz Wanzenböck <moritz.wanzenboeck@linbit.com>
|
||||
Jenni Griesmann <jgriesmann@digitalocean.com>
|
||||
|
3
vendor/github.com/digitalocean/go-libvirt/CONTRIBUTING.md
generated
vendored
3
vendor/github.com/digitalocean/go-libvirt/CONTRIBUTING.md
generated
vendored
@ -25,6 +25,3 @@ 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.
|
||||
|
121
vendor/github.com/digitalocean/go-libvirt/README.md
generated
vendored
121
vendor/github.com/digitalocean/go-libvirt/README.md
generated
vendored
@ -1,10 +1,13 @@
|
||||
libvirt [](http://godoc.org/github.com/digitalocean/go-libvirt) [](https://travis-ci.org/digitalocean/go-libvirt) [](https://goreportcard.com/report/github.com/digitalocean/go-libvirt)
|
||||
libvirt
|
||||
[](http://godoc.org/github.com/digitalocean/go-libvirt)
|
||||
[](https://github.com/digitalocean/go-libvirt/actions/)
|
||||
[](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).
|
||||
libvirt's RPC interface, as documented [here](https://libvirt.org/kbase/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).
|
||||
|
||||
@ -30,10 +33,15 @@ re-run the code generator. To do this, follow these steps:
|
||||
|
||||
- First, download a copy of the libvirt sources corresponding to the version you
|
||||
want to use.
|
||||
- Next, run `autogen.sh` in the libvirt directory. The autotools will check for
|
||||
necessary libraries and prepare libvirt for building. We don't actually need
|
||||
to build libvirt, but we do require some header files that are produced in
|
||||
this step.
|
||||
- Change directories into where you've unpacked your distribution of libvirt.
|
||||
- The second step depends on the version of libvirt you'd like to build against.
|
||||
It's not necessary to actually build libvirt, but it is necessary to run libvirt's
|
||||
"configure" step because it generates required files.
|
||||
- For libvirt < v6.7.0:
|
||||
- `$ mkdir build; cd build`
|
||||
- `$ ../autogen.sh`
|
||||
- For libvirt >= v6.7.0:
|
||||
- `$ meson setup build`
|
||||
- Finally, set the environment variable `LIBVIRT_SOURCE` to the directory you
|
||||
put libvirt into, and run `go generate ./...` from the go-libvirt directory.
|
||||
This runs both of the go-libvirt's code generators.
|
||||
@ -169,3 +177,104 @@ ID Name UUID
|
||||
1 Test-1 dc329f87d4de47198cfd2e21c6105b01
|
||||
2 Test-2 dc229f87d4de47198cfd2e21c6105b01
|
||||
```
|
||||
|
||||
Example (Connect to libvirt via TLS over TCP)
|
||||
-------
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"github.com/digitalocean/go-libvirt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// This dials libvirt on the local machine
|
||||
// It connects to libvirt via TLS over TCP
|
||||
// To connect to a remote machine, you need to have the ca/cert/key of it.
|
||||
keyFileXML, err := ioutil.ReadFile("/etc/pki/libvirt/private/clientkey.pem")
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
certFileXML, err := ioutil.ReadFile("/etc/pki/libvirt/clientcert.pem")
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
caFileXML, err := ioutil.ReadFile("/etc/pki/CA/cacert.pem")
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
cert, err := tls.X509KeyPair([]byte(certFileXML), []byte(keyFileXML))
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
roots := x509.NewCertPool()
|
||||
roots.AppendCertsFromPEM([]byte(caFileXML))
|
||||
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
RootCAs: roots,
|
||||
}
|
||||
|
||||
// Use host name or IP which is valid in certificate
|
||||
addr := "10.10.10.10"
|
||||
port := "16514"
|
||||
c, err := tls.Dial("tcp", addr + ":" + port, config)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to dial libvirt: %v", err)
|
||||
}
|
||||
|
||||
// Drop a byte before libvirt.New(c)
|
||||
// More details at https://github.com/digitalocean/go-libvirt/issues/89
|
||||
// Remove this line if the issue does not exist any more
|
||||
c.Read(make([]byte, 1))
|
||||
|
||||
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)
|
||||
|
||||
// Return both running and stopped VMs
|
||||
flags := libvirt.ConnectListDomainsActive | libvirt.ConnectListDomainsInactive
|
||||
domains, _, err := l.ConnectListAllDomains(1, flags)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to retrieve domains: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("ID\tName\t\tUUID")
|
||||
fmt.Println("--------------------------------------------------------")
|
||||
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)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Running the Integration Tests
|
||||
-----------------------------
|
||||
|
||||
Github actions workflows are defined in .github/worflows and can be triggered
|
||||
manually in the github GUI after pushing a branch. There are not currently
|
||||
convenient scripts for setting up and running integration tests locally, but
|
||||
installing libvirt and defining only the artifacts described by the files in
|
||||
testdata should be sufficient to be able to run the integration test file against.
|
||||
|
||||
|
1102
vendor/github.com/digitalocean/go-libvirt/const.gen.go
generated
vendored
1102
vendor/github.com/digitalocean/go-libvirt/const.gen.go
generated
vendored
File diff suppressed because it is too large
Load Diff
116
vendor/github.com/digitalocean/go-libvirt/doc.go
generated
vendored
116
vendor/github.com/digitalocean/go-libvirt/doc.go
generated
vendored
@ -12,65 +12,59 @@
|
||||
// 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 is a pure Go interface to 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.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// 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)
|
||||
// }
|
||||
// }
|
||||
package libvirt
|
||||
|
4
vendor/github.com/digitalocean/go-libvirt/internal/constants/remote_protocol.gen.go
generated
vendored
4
vendor/github.com/digitalocean/go-libvirt/internal/constants/remote_protocol.gen.go
generated
vendored
@ -881,6 +881,8 @@ const (
|
||||
ProcDomainAuthorizedSshKeysGet = 424
|
||||
// ProcDomainAuthorizedSshKeysSet is libvirt's REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_SET
|
||||
ProcDomainAuthorizedSshKeysSet = 425
|
||||
// ProcDomainGetMessages is libvirt's REMOTE_PROC_DOMAIN_GET_MESSAGES
|
||||
ProcDomainGetMessages = 426
|
||||
|
||||
|
||||
// From consts:
|
||||
@ -1010,6 +1012,8 @@ const (
|
||||
NetworkPortParametersMax = 16
|
||||
// DomainAuthorizedSshKeysMax is libvirt's REMOTE_DOMAIN_AUTHORIZED_SSH_KEYS_MAX
|
||||
DomainAuthorizedSshKeysMax = 2048
|
||||
// DomainMessagesMax is libvirt's REMOTE_DOMAIN_MESSAGES_MAX
|
||||
DomainMessagesMax = 2048
|
||||
// DomainEventGraphicsIdentityMax is libvirt's REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX
|
||||
DomainEventGraphicsIdentityMax = 20
|
||||
// Program is libvirt's REMOTE_PROGRAM
|
||||
|
150
vendor/github.com/digitalocean/go-libvirt/internal/event/stream.go
generated
vendored
150
vendor/github.com/digitalocean/go-libvirt/internal/event/stream.go
generated
vendored
@ -14,7 +14,16 @@
|
||||
|
||||
package event
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// emptyEvent is used as a zero-value. Clients will never receive one of these;
|
||||
// they are only here to satisfy the compiler. See the comments in process() for
|
||||
// more information.
|
||||
type emptyEvent struct{}
|
||||
|
||||
func (emptyEvent) GetCallbackID() int32 { return 0 }
|
||||
|
||||
// Stream is an unbounded buffered event channel. The implementation
|
||||
// consists of a pair of unbuffered channels and a goroutine to manage them.
|
||||
@ -28,12 +37,45 @@ type Stream struct {
|
||||
|
||||
// manage unbounded channel behavior.
|
||||
queue []Event
|
||||
qlen chan (chan int)
|
||||
in, out chan Event
|
||||
|
||||
// terminates processing
|
||||
shutdown context.CancelFunc
|
||||
}
|
||||
|
||||
// NewStream configures a new Event Stream. Incoming events are appended to a
|
||||
// queue, which is then relayed to the listening client. Client behavior will
|
||||
// not cause incoming events to block. It is the responsibility of the caller
|
||||
// to terminate the Stream via Shutdown() when no longer in use.
|
||||
func NewStream(program uint32, cbID int32) *Stream {
|
||||
s := &Stream{
|
||||
Program: program,
|
||||
CallbackID: cbID,
|
||||
in: make(chan Event),
|
||||
out: make(chan Event),
|
||||
qlen: make(chan (chan int)),
|
||||
}
|
||||
|
||||
// Start the processing loop, which will return a routine we can use to
|
||||
// shut the queue down later.
|
||||
s.shutdown = s.start()
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Len will return the current count of events in the internal queue for a
|
||||
// stream. It does this by sending a message to the stream's process() loop,
|
||||
// which will then write the current length to the channel contained in that
|
||||
// message.
|
||||
func (s *Stream) Len() int {
|
||||
// Send a request to the process() loop to get the current length of the
|
||||
// queue
|
||||
ch := make(chan int)
|
||||
s.qlen <- ch
|
||||
return <-ch
|
||||
}
|
||||
|
||||
// Recv returns the next available event from the Stream's queue.
|
||||
func (s *Stream) Recv() chan Event {
|
||||
return s.out
|
||||
@ -44,9 +86,9 @@ func (s *Stream) Push(e Event) {
|
||||
s.in <- e
|
||||
}
|
||||
|
||||
// Shutdown gracefully terminates Stream processing, releasing all
|
||||
// internal resources. Events which have not yet been received by the client
|
||||
// will be dropped. Subsequent calls to Shutdown() are idempotent.
|
||||
// Shutdown gracefully terminates Stream processing, releasing all internal
|
||||
// resources. Events which have not yet been received by the client will be
|
||||
// dropped. Subsequent calls to Shutdown() are idempotent.
|
||||
func (s *Stream) Shutdown() {
|
||||
if s.shutdown != nil {
|
||||
s.shutdown()
|
||||
@ -54,8 +96,7 @@ func (s *Stream) Shutdown() {
|
||||
}
|
||||
|
||||
// start starts the event processing loop, which will continue to run until
|
||||
// terminated by the returned context.CancelFunc. Starting a previously started
|
||||
// Stream is an idempotent operation.
|
||||
// terminated by the returned context.CancelFunc.
|
||||
func (s *Stream) start() context.CancelFunc {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
@ -64,82 +105,53 @@ func (s *Stream) start() context.CancelFunc {
|
||||
return cancel
|
||||
}
|
||||
|
||||
// process manages an Stream's lifecycle until canceled by the provided
|
||||
// context. Incoming events are appended to a queue which is then relayed to
|
||||
// the a listening client. New events pushed onto the queue will not block due
|
||||
// to client behavior.
|
||||
// process manages an Stream's lifecycle until canceled by the provided context.
|
||||
// Incoming events are appended to a queue which is then relayed to the
|
||||
// listening client. New events pushed onto the queue will not block if the
|
||||
// client is not actively polling for them; the stream will buffer them
|
||||
// internally.
|
||||
func (s *Stream) process(ctx context.Context) {
|
||||
defer func() {
|
||||
close(s.in)
|
||||
close(s.out)
|
||||
}()
|
||||
// Close the output channel so that clients know this stream is finished.
|
||||
// We don't close s.in to avoid creating a race with the stream's Push()
|
||||
// function.
|
||||
defer close(s.out)
|
||||
|
||||
// This function is used to retrieve the next event from the queue, to be
|
||||
// sent to the client. If there are no more events to send, it returns a nil
|
||||
// channel and a zero-value event.
|
||||
nextEvent := func() (chan Event, Event) {
|
||||
sendCh := chan Event(nil)
|
||||
next := Event(emptyEvent{})
|
||||
if len(s.queue) > 0 {
|
||||
sendCh = s.out
|
||||
next = s.queue[0]
|
||||
}
|
||||
return sendCh, next
|
||||
}
|
||||
|
||||
// The select statement in this loop relies on the fact that a send to a nil
|
||||
// channel will block forever. If we have no entries in the queue, the
|
||||
// sendCh variable will be nil, so the clause that attempts to send an event
|
||||
// to the client will never complete. Clients will never receive an
|
||||
// emptyEvent.
|
||||
for {
|
||||
// informs send() to stop trying
|
||||
nctx, next := context.WithCancel(ctx)
|
||||
defer next()
|
||||
sendCh, nextEvt := nextEvent()
|
||||
|
||||
select {
|
||||
// new event received, append to queue
|
||||
case e := <-s.in:
|
||||
s.queue = append(s.queue, e)
|
||||
|
||||
// client recieved an event, pop from queue
|
||||
case <-s.send(nctx):
|
||||
if len(s.queue) > 1 {
|
||||
s.queue = s.queue[1:]
|
||||
} else {
|
||||
s.queue = []Event{}
|
||||
}
|
||||
case lenCh := <-s.qlen:
|
||||
lenCh <- len(s.queue)
|
||||
|
||||
// client received an event, pop from queue
|
||||
case sendCh <- nextEvt:
|
||||
s.queue = s.queue[1:]
|
||||
|
||||
// shutdown requested
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
// send returns a channel which blocks until either the first item on the queue
|
||||
// (if existing) is sent to the client, or the provided context is canceled.
|
||||
// The stream's queue is never modified.
|
||||
func (s *Stream) send(ctx context.Context) <-chan struct{} {
|
||||
ch := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(ch)
|
||||
|
||||
// do nothing and block if the queue is empty
|
||||
if len(s.queue) == 0 {
|
||||
<-ctx.Done()
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, attempt to send the event
|
||||
select {
|
||||
case s.out <- s.queue[0]:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// NewStream configures a new Event Stream. Incoming events are appended to a
|
||||
// queue, which is then relayed to the listening client. Client behavior will
|
||||
// not cause incoming events to block. It is the responsibility of the caller
|
||||
// to terminate the Stream via Shutdown() when no longer in use.
|
||||
func NewStream(program uint32, cbID int32) *Stream {
|
||||
ic := &Stream{
|
||||
Program: program,
|
||||
CallbackID: cbID,
|
||||
in: make(chan Event),
|
||||
out: make(chan Event),
|
||||
}
|
||||
|
||||
ic.shutdown = ic.start()
|
||||
|
||||
return ic
|
||||
}
|
||||
|
245
vendor/github.com/digitalocean/go-libvirt/libvirt.go
generated
vendored
245
vendor/github.com/digitalocean/go-libvirt/libvirt.go
generated
vendored
@ -12,8 +12,6 @@
|
||||
// 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
|
||||
@ -21,7 +19,6 @@ package libvirt
|
||||
//go:generate scripts/gen-consts.sh
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
@ -29,22 +26,47 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/digitalocean/go-libvirt/internal/constants"
|
||||
"github.com/digitalocean/go-libvirt/internal/event"
|
||||
xdr "github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2"
|
||||
"github.com/digitalocean/go-libvirt/socket"
|
||||
"github.com/digitalocean/go-libvirt/socket/dialers"
|
||||
)
|
||||
|
||||
// ErrEventsNotSupported is returned by Events() if event streams
|
||||
// are unsupported by either QEMU or libvirt.
|
||||
var ErrEventsNotSupported = errors.New("event monitor is not supported")
|
||||
|
||||
// ConnectURI defines a type for driver URIs for libvirt
|
||||
// the defined constants are *not* exhaustive as there are also options
|
||||
// e.g. to connect remote via SSH
|
||||
type ConnectURI string
|
||||
|
||||
const (
|
||||
// QEMUSystem connects to a QEMU system mode daemon
|
||||
QEMUSystem ConnectURI = "qemu:///system"
|
||||
// QEMUSession connects to a QEMU session mode daemon (unprivileged)
|
||||
QEMUSession ConnectURI = "qemu:///session"
|
||||
// XenSystem connects to a Xen system mode daemon
|
||||
XenSystem ConnectURI = "xen:///system"
|
||||
//TestDefault connect to default mock driver
|
||||
TestDefault ConnectURI = "test:///default"
|
||||
|
||||
// disconnectedTimeout is how long to wait for disconnect cleanup to
|
||||
// complete
|
||||
disconnectTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
// Libvirt implements libvirt's remote procedure call protocol.
|
||||
type Libvirt struct {
|
||||
conn net.Conn
|
||||
r *bufio.Reader
|
||||
w *bufio.Writer
|
||||
mu *sync.Mutex
|
||||
// socket connection
|
||||
socket *socket.Socket
|
||||
// closed after cleanup complete following the underlying connection to
|
||||
// libvirt being disconnected.
|
||||
disconnected chan struct{}
|
||||
|
||||
// method callbacks
|
||||
cmux sync.RWMutex
|
||||
@ -93,16 +115,39 @@ func (l *Libvirt) Capabilities() ([]byte, error) {
|
||||
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 {
|
||||
// called at connection time, authenticating with all supported auth types
|
||||
func (l *Libvirt) authenticate() error {
|
||||
// libvirt requires that we call auth-list prior to connecting,
|
||||
// even when no authentication is used.
|
||||
resp, err := l.AuthList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, auth := range resp {
|
||||
switch auth {
|
||||
case constants.AuthNone:
|
||||
case constants.AuthPolkit:
|
||||
_, err := l.AuthPolkit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Libvirt) initLibvirtComms(uri ConnectURI) error {
|
||||
payload := struct {
|
||||
Padding [3]byte
|
||||
Name string
|
||||
Flags uint32
|
||||
}{
|
||||
Padding: [3]byte{0x1, 0x0, 0x0},
|
||||
Name: "qemu:///system",
|
||||
Name: string(uri),
|
||||
Flags: 0,
|
||||
}
|
||||
|
||||
@ -111,9 +156,7 @@ func (l *Libvirt) Connect() error {
|
||||
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)
|
||||
err = l.authenticate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -126,24 +169,76 @@ func (l *Libvirt) Connect() error {
|
||||
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 _, ev := range l.events {
|
||||
l.unsubscribeEvents(ev)
|
||||
}
|
||||
|
||||
// Deregister all callbacks to prevent blocking on clients with
|
||||
// outstanding requests
|
||||
l.deregisterAll()
|
||||
|
||||
_, err := l.request(constants.ProcConnectClose, constants.Program, nil)
|
||||
// ConnectToURI establishes communication with the specified libvirt driver
|
||||
// The underlying libvirt socket connection will be created via the dialer.
|
||||
// Since the connection can be lost, the Disconnected function can be used
|
||||
// to monitor for a lost connection.
|
||||
func (l *Libvirt) ConnectToURI(uri ConnectURI) error {
|
||||
err := l.socket.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return l.conn.Close()
|
||||
// Start watching the underlying socket connection immediately.
|
||||
// If we don't, and Libvirt goes away partway through initLibvirtComms,
|
||||
// then the callbacks that initLibvirtComms has registered will never
|
||||
// be closed, and therefore it will be stuck waiting for data from a
|
||||
// channel that will never arrive.
|
||||
go l.waitAndDisconnect()
|
||||
|
||||
err = l.initLibvirtComms(uri)
|
||||
if err != nil {
|
||||
l.socket.Disconnect()
|
||||
return err
|
||||
}
|
||||
|
||||
l.disconnected = make(chan struct{})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Connect establishes communication with the libvirt server.
|
||||
// The underlying libvirt socket connection will be created via the dialer.
|
||||
// Since the connection can be lost, the Disconnected function can be used
|
||||
// to monitor for a lost connection.
|
||||
func (l *Libvirt) Connect() error {
|
||||
return l.ConnectToURI(QEMUSystem)
|
||||
}
|
||||
|
||||
// Disconnect shuts down communication with the libvirt server and closes the
|
||||
// underlying net.Conn.
|
||||
func (l *Libvirt) Disconnect() error {
|
||||
// Ordering is important here. We want to make sure the connection is closed
|
||||
// before unsubscribing and deregistering the events and requests, to
|
||||
// prevent new requests from racing.
|
||||
_, err := l.request(constants.ProcConnectClose, constants.Program, nil)
|
||||
|
||||
// syscall.EINVAL is returned by the socket pkg when things have already
|
||||
// been disconnected.
|
||||
if err != nil && err != syscall.EINVAL {
|
||||
return err
|
||||
}
|
||||
err = l.socket.Disconnect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// wait for the listen goroutine to detect the lost connection and clean up
|
||||
// to happen once it returns. Safeguard with a timeout.
|
||||
// Things not fully cleaned up is better than a deadlock.
|
||||
select {
|
||||
case <-l.disconnected:
|
||||
case <-time.After(disconnectTimeout):
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Disconnected allows callers to detect if the underlying connection
|
||||
// to libvirt has been closed. If the returned channel is closed, then
|
||||
// the connection to libvirt has been lost (or disconnected intentionally).
|
||||
func (l *Libvirt) Disconnected() <-chan struct{} {
|
||||
return l.disconnected
|
||||
}
|
||||
|
||||
// Domains returns a list of all domains managed by libvirt.
|
||||
@ -192,7 +287,7 @@ func (l *Libvirt) SubscribeQEMUEvents(ctx context.Context, dom string) (<-chan D
|
||||
defer cancel()
|
||||
defer l.unsubscribeQEMUEvents(stream)
|
||||
defer stream.Shutdown()
|
||||
defer func() { close(ch) }()
|
||||
defer close(ch)
|
||||
|
||||
for {
|
||||
select {
|
||||
@ -260,10 +355,10 @@ func (l *Libvirt) SubscribeEvents(ctx context.Context, eventID DomainEventID,
|
||||
|
||||
// unsubscribeEvents stops the flow of the specified events from libvirt. There
|
||||
// are two steps to this process: a call to libvirt to deregister our callback,
|
||||
// and then removing the callback from the list used by the `route` fucntion. If
|
||||
// and then removing the callback from the list used by the `Route` function. If
|
||||
// the deregister call fails, we'll return the error, but still remove the
|
||||
// callback from the list. That's ok; if any events arrive after this point, the
|
||||
// route function will drop them when it finds no registered handler.
|
||||
// Route function will drop them when it finds no registered handler.
|
||||
func (l *Libvirt) unsubscribeEvents(stream *event.Stream) error {
|
||||
err := l.ConnectDomainEventCallbackDeregisterAny(stream.CallbackID)
|
||||
l.removeStream(stream.CallbackID)
|
||||
@ -590,19 +685,85 @@ func getQEMUError(r response) error {
|
||||
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[int32]chan response),
|
||||
events: make(map[int32]*event.Stream),
|
||||
func (l *Libvirt) waitAndDisconnect() {
|
||||
// wait for the socket to indicate if/when it's been disconnected
|
||||
<-l.socket.Disconnected()
|
||||
|
||||
// close event streams
|
||||
l.removeAllStreams()
|
||||
|
||||
// Deregister all callbacks to prevent blocking on clients with
|
||||
// outstanding requests
|
||||
l.deregisterAll()
|
||||
|
||||
select {
|
||||
case <-l.disconnected:
|
||||
// l.disconnected is already closed, i.e., Libvirt.ConnectToURI
|
||||
// was unable to complete all phases of its connection and
|
||||
// so this hadn't been assigned to an open channel yet (it
|
||||
// is set to a closed channel in Libvirt.New*)
|
||||
//
|
||||
// Just return to avoid closing an already-closed channel.
|
||||
return
|
||||
default:
|
||||
// if we make it here then reading from l.disconnected is blocking,
|
||||
// which suggests that it is open and must be closed.
|
||||
}
|
||||
|
||||
go l.listen()
|
||||
close(l.disconnected)
|
||||
}
|
||||
|
||||
// NewWithDialer configures a new Libvirt object that can be used to perform
|
||||
// RPCs via libvirt's socket. The actual connection will not be established
|
||||
// until Connect is called. The same Libvirt object may be used to re-connect
|
||||
// multiple times.
|
||||
func NewWithDialer(dialer socket.Dialer) *Libvirt {
|
||||
l := &Libvirt{
|
||||
s: 0,
|
||||
disconnected: make(chan struct{}),
|
||||
callbacks: make(map[int32]chan response),
|
||||
events: make(map[int32]*event.Stream),
|
||||
}
|
||||
|
||||
l.socket = socket.New(dialer, l)
|
||||
|
||||
// we start with a closed channel since that indicates no connection
|
||||
close(l.disconnected)
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// New configures a new Libvirt RPC connection.
|
||||
// This function only remains to retain backwards compatability.
|
||||
// When Libvirt's Connect function is called, the Dial will simply return the
|
||||
// connection passed in here and start a goroutine listening/reading from it.
|
||||
// If at any point the Disconnect function is called, any subsequent Connect
|
||||
// call will simply return an already closed connection.
|
||||
//
|
||||
// Deprecated: Please use NewWithDialer.
|
||||
func New(conn net.Conn) *Libvirt {
|
||||
return NewWithDialer(dialers.NewAlreadyConnected(conn))
|
||||
}
|
||||
|
||||
// NetworkUpdateCompat is a wrapper over NetworkUpdate which swaps `Command` and `Section` when needed.
|
||||
// This function must be used instead of NetworkUpdate to be sure that the
|
||||
// NetworkUpdate call works both with older and newer libvirtd connections.
|
||||
//
|
||||
// libvirt on-wire protocol had a bug for a long time where Command and Section
|
||||
// were reversed. It's been fixed in newer libvirt versions, and backported to
|
||||
// some older versions. This helper detects what argument order libvirtd expects
|
||||
// and makes the correct NetworkUpdate call.
|
||||
func (l *Libvirt) NetworkUpdateCompat(Net Network, Command NetworkUpdateCommand, Section NetworkUpdateSection, ParentIndex int32, XML string, Flags NetworkUpdateFlags) (err error) {
|
||||
// This is defined in libvirt/src/libvirt_internal.h and thus not available in go-libvirt autogenerated code
|
||||
const virDrvFeatureNetworkUpdateHasCorrectOrder = 16
|
||||
hasCorrectOrder, err := l.ConnectSupportsFeature(virDrvFeatureNetworkUpdateHasCorrectOrder)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to confirm argument order for NetworkUpdate: %w", err)
|
||||
}
|
||||
|
||||
// https://gitlab.com/libvirt/libvirt/-/commit/b0f78d626a18bcecae3a4d165540ab88bfbfc9ee
|
||||
if hasCorrectOrder == 0 {
|
||||
return l.NetworkUpdate(Net, uint32(Section), uint32(Command), ParentIndex, XML, Flags)
|
||||
}
|
||||
return l.NetworkUpdate(Net, uint32(Command), uint32(Section), ParentIndex, XML, Flags)
|
||||
}
|
||||
|
4
vendor/github.com/digitalocean/go-libvirt/libvirt.yml
generated
vendored
4
vendor/github.com/digitalocean/go-libvirt/libvirt.yml
generated
vendored
@ -27,7 +27,7 @@ PARSER:
|
||||
# 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]
|
||||
IncludePaths: [./lv_source/include, ./lv_source/build/include]
|
||||
SourcesPaths:
|
||||
- libvirt/libvirt.h
|
||||
- libvirt/virterror.h
|
||||
@ -56,7 +56,7 @@ TRANSLATOR:
|
||||
- {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)"}
|
||||
- {transform: unexport, from: "^From"}
|
||||
const:
|
||||
- {action: accept, from: "^VIR_"}
|
||||
# Special case to prevent a collision with a type:
|
||||
|
7
vendor/github.com/digitalocean/go-libvirt/libvirtd.conf
generated
vendored
7
vendor/github.com/digitalocean/go-libvirt/libvirtd.conf
generated
vendored
@ -1,7 +0,0 @@
|
||||
# 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"
|
55
vendor/github.com/digitalocean/go-libvirt/remote_protocol.gen.go
generated
vendored
55
vendor/github.com/digitalocean/go-libvirt/remote_protocol.gen.go
generated
vendored
@ -147,8 +147,8 @@ type DomainSnapshot struct {
|
||||
Dom Domain
|
||||
}
|
||||
|
||||
// Error is libvirt's remote_error
|
||||
type Error struct {
|
||||
// remote_error is libvirt's remote_error
|
||||
type remote_error struct {
|
||||
Code int32
|
||||
OptDomain int32
|
||||
Message OptString
|
||||
@ -191,7 +191,7 @@ type NodeGetMemoryStats struct {
|
||||
// DomainDiskError is libvirt's remote_domain_disk_error
|
||||
type DomainDiskError struct {
|
||||
Disk string
|
||||
Error int32
|
||||
remote_error int32
|
||||
}
|
||||
|
||||
// ConnectOpenArgs is libvirt's remote_connect_open_args
|
||||
@ -1371,7 +1371,7 @@ type DomainGetCPUStatsRet struct {
|
||||
// DomainGetHostnameArgs is libvirt's remote_domain_get_hostname_args
|
||||
type DomainGetHostnameArgs struct {
|
||||
Dom Domain
|
||||
Flags uint32
|
||||
Flags DomainGetHostnameFlags
|
||||
}
|
||||
|
||||
// DomainGetHostnameRet is libvirt's remote_domain_get_hostname_ret
|
||||
@ -4119,6 +4119,17 @@ type DomainAuthorizedSshKeysSetArgs struct {
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
// DomainGetMessagesArgs is libvirt's remote_domain_get_messages_args
|
||||
type DomainGetMessagesArgs struct {
|
||||
Dom Domain
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
// DomainGetMessagesRet is libvirt's remote_domain_get_messages_ret
|
||||
type DomainGetMessagesRet struct {
|
||||
Msgs []string
|
||||
}
|
||||
|
||||
|
||||
// TypedParamValue is a discriminated union.
|
||||
type TypedParamValue struct {
|
||||
@ -12387,7 +12398,7 @@ func (l *Libvirt) DomainEventBalloonChange() (err error) {
|
||||
}
|
||||
|
||||
// DomainGetHostname is the go wrapper for REMOTE_PROC_DOMAIN_GET_HOSTNAME.
|
||||
func (l *Libvirt) DomainGetHostname(Dom Domain, Flags uint32) (rHostname string, err error) {
|
||||
func (l *Libvirt) DomainGetHostname(Dom Domain, Flags DomainGetHostnameFlags) (rHostname string, err error) {
|
||||
var buf []byte
|
||||
|
||||
args := DomainGetHostnameArgs {
|
||||
@ -16447,3 +16458,37 @@ func (l *Libvirt) DomainAuthorizedSshKeysSet(Dom Domain, User string, Keys []str
|
||||
return
|
||||
}
|
||||
|
||||
// DomainGetMessages is the go wrapper for REMOTE_PROC_DOMAIN_GET_MESSAGES.
|
||||
func (l *Libvirt) DomainGetMessages(Dom Domain, Flags uint32) (rMsgs []string, err error) {
|
||||
var buf []byte
|
||||
|
||||
args := DomainGetMessagesArgs {
|
||||
Dom: Dom,
|
||||
Flags: Flags,
|
||||
}
|
||||
|
||||
buf, err = encode(&args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var r response
|
||||
r, err = l.requestStream(426, constants.Program, buf, nil, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Return value unmarshaling
|
||||
tpd := typedParamDecoder{}
|
||||
ct := map[string]xdr.TypeDecoder{"libvirt.TypedParam": tpd}
|
||||
rdr := bytes.NewReader(r.Payload)
|
||||
dec := xdr.NewDecoderCustomTypes(rdr, 0, ct)
|
||||
// Msgs: []string
|
||||
_, err = dec.Decode(&rMsgs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
295
vendor/github.com/digitalocean/go-libvirt/rpc.go
generated
vendored
295
vendor/github.com/digitalocean/go-libvirt/rpc.go
generated
vendored
@ -16,166 +16,55 @@ package libvirt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"github.com/digitalocean/go-libvirt/internal/constants"
|
||||
"github.com/digitalocean/go-libvirt/internal/event"
|
||||
xdr "github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2"
|
||||
"github.com/digitalocean/go-libvirt/socket"
|
||||
)
|
||||
|
||||
// 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 int32
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Global packet instance, for use with unsafe.Sizeof()
|
||||
var _p packet
|
||||
|
||||
// internal rpc response
|
||||
type response struct {
|
||||
Payload []byte
|
||||
Status uint32
|
||||
}
|
||||
|
||||
// libvirt error response
|
||||
type libvirtError struct {
|
||||
Code uint32
|
||||
DomainID uint32
|
||||
Padding uint8
|
||||
Message string
|
||||
Level uint32
|
||||
// Error reponse from libvirt
|
||||
type Error struct {
|
||||
Code uint32
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e libvirtError) Error() string {
|
||||
func (e Error) 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)
|
||||
func checkError(err error, expectedError ErrorNumber) bool {
|
||||
for err != nil {
|
||||
e, ok := err.(Error)
|
||||
if ok {
|
||||
return e.Code == uint32(expectedError)
|
||||
}
|
||||
err = errors.Unwrap(err)
|
||||
}
|
||||
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) - int(unsafe.Sizeof(_p))
|
||||
buf := make([]byte, size)
|
||||
_, err = io.ReadFull(l.r, buf)
|
||||
if err != nil {
|
||||
// invalid packet
|
||||
continue
|
||||
}
|
||||
|
||||
// route response to caller
|
||||
l.route(h, buf)
|
||||
}
|
||||
return checkError(err, ErrNoDomain)
|
||||
}
|
||||
|
||||
// callback sends RPC responses to respective callers.
|
||||
@ -191,9 +80,9 @@ func (l *Libvirt) callback(id int32, res response) {
|
||||
c <- res
|
||||
}
|
||||
|
||||
// route sends incoming packets to their listeners.
|
||||
func (l *Libvirt) route(h *header, buf []byte) {
|
||||
// route events to their respective listener
|
||||
// Route sends incoming packets to their listeners.
|
||||
func (l *Libvirt) Route(h *socket.Header, buf []byte) {
|
||||
// Route events to their respective listener
|
||||
var event event.Event
|
||||
|
||||
switch {
|
||||
@ -243,24 +132,36 @@ func (l *Libvirt) addStream(s *event.Stream) {
|
||||
l.events[s.CallbackID] = s
|
||||
}
|
||||
|
||||
// removeStream notifies the libvirt server to stop sending events for the
|
||||
// provided callback ID. Upon successful de-registration the callback handler
|
||||
// is destroyed. Subsequent calls to removeStream are idempotent and return
|
||||
// nil.
|
||||
// TODO: Fix this comment
|
||||
// removeStream deletes an event stream. The caller should first notify libvirt
|
||||
// to stop sending events for this stream. Subsequent calls to removeStream are
|
||||
// idempotent and return nil.
|
||||
func (l *Libvirt) removeStream(id int32) error {
|
||||
l.emux.Lock()
|
||||
defer l.emux.Unlock()
|
||||
|
||||
// if the event is already removed, just return nil
|
||||
_, ok := l.events[id]
|
||||
q, ok := l.events[id]
|
||||
if ok {
|
||||
delete(l.events, id)
|
||||
q.Shutdown()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// removeAllStreams deletes all event streams. This is meant to be used to
|
||||
// clean up only once the underlying connection to libvirt is disconnected and
|
||||
// thus does not attempt to notify libvirt to stop sending events.
|
||||
func (l *Libvirt) removeAllStreams() {
|
||||
l.emux.Lock()
|
||||
defer l.emux.Unlock()
|
||||
|
||||
for _, ev := range l.events {
|
||||
ev.Shutdown()
|
||||
delete(l.events, ev.CallbackID)
|
||||
}
|
||||
}
|
||||
|
||||
// register configures a method response callback
|
||||
func (l *Libvirt) register(id int32, c chan response) {
|
||||
l.cmux.Lock()
|
||||
@ -316,7 +217,8 @@ func (l *Libvirt) requestStream(proc uint32, program uint32, payload []byte,
|
||||
l.deregister(serial)
|
||||
}()
|
||||
|
||||
err := l.sendPacket(serial, proc, program, payload, Call, StatusOK)
|
||||
err := l.socket.SendPacket(serial, proc, program, payload, socket.Call,
|
||||
socket.StatusOK)
|
||||
if err != nil {
|
||||
return response{}, err
|
||||
}
|
||||
@ -330,7 +232,7 @@ func (l *Libvirt) requestStream(proc uint32, program uint32, payload []byte,
|
||||
abort := make(chan bool)
|
||||
outErr := make(chan error)
|
||||
go func() {
|
||||
outErr <- l.sendStream(serial, proc, program, out, abort)
|
||||
outErr <- l.socket.SendStream(serial, proc, program, out, abort)
|
||||
}()
|
||||
|
||||
// Even without incoming stream server sends confirmation once all data is received
|
||||
@ -365,7 +267,7 @@ func (l *Libvirt) processIncomingStream(c chan response, inStream io.Writer) (re
|
||||
}
|
||||
|
||||
// StatusOK indicates end of stream
|
||||
if resp.Status == StatusOK {
|
||||
if resp.Status == socket.StatusOK {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@ -386,77 +288,9 @@ func (l *Libvirt) processIncomingStream(c chan response, inStream io.Writer) (re
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Libvirt) sendStream(serial int32, 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-unsafe.Sizeof(_p))
|
||||
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 int32, proc uint32, program uint32, payload []byte, typ uint32, status uint32) error {
|
||||
|
||||
p := packet{
|
||||
Header: header{
|
||||
Program: program,
|
||||
Version: constants.ProtocolVersion,
|
||||
Procedure: proc,
|
||||
Type: typ,
|
||||
Serial: serial,
|
||||
Status: status,
|
||||
},
|
||||
}
|
||||
|
||||
size := int(unsafe.Sizeof(p.Len)) + int(unsafe.Sizeof(p.Header))
|
||||
if payload != nil {
|
||||
size += len(payload)
|
||||
}
|
||||
p.Len = uint32(size)
|
||||
|
||||
// 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 {
|
||||
if resp.Status == socket.StatusError {
|
||||
return resp, decodeError(resp.Payload)
|
||||
}
|
||||
|
||||
@ -473,9 +307,15 @@ func encode(data interface{}) ([]byte, error) {
|
||||
|
||||
// decodeError extracts an error message from the provider buffer.
|
||||
func decodeError(buf []byte) error {
|
||||
var e libvirtError
|
||||
|
||||
dec := xdr.NewDecoder(bytes.NewReader(buf))
|
||||
|
||||
e := struct {
|
||||
Code uint32
|
||||
DomainID uint32
|
||||
Padding uint8
|
||||
Message string
|
||||
Level uint32
|
||||
}{}
|
||||
_, err := dec.Decode(&e)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -484,12 +324,13 @@ func decodeError(buf []byte) error {
|
||||
if strings.Contains(e.Message, "unknown procedure") {
|
||||
return ErrUnsupported
|
||||
}
|
||||
|
||||
// if libvirt returns ERR_OK, ignore the error
|
||||
if checkError(e, errOk) {
|
||||
if ErrorNumber(e.Code) == ErrOk {
|
||||
return nil
|
||||
}
|
||||
|
||||
return e
|
||||
return Error{Code: uint32(e.Code), Message: e.Message}
|
||||
}
|
||||
|
||||
// eventDecoder decodes an event from a xdr buffer.
|
||||
@ -499,40 +340,6 @@ func eventDecoder(buf []byte, e interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// pktlen returns the length of an incoming RPC packet. Read errors will
|
||||
// result in a returned response length of 0 and a non-nil error.
|
||||
func pktlen(r io.Reader) (uint32, error) {
|
||||
buf := make([]byte, unsafe.Sizeof(_p.Len))
|
||||
|
||||
// extract the packet's length from the header
|
||||
_, err := io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
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, unsafe.Sizeof(_p.Header))
|
||||
|
||||
// extract the packet's header from r
|
||||
_, err := io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &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: int32(binary.BigEndian.Uint32(buf[16:20])),
|
||||
Status: binary.BigEndian.Uint32(buf[20:24]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type typedParamDecoder struct{}
|
||||
|
||||
// Decode decodes a TypedParam. These are part of the libvirt spec, and not xdr
|
||||
|
26
vendor/github.com/digitalocean/go-libvirt/socket/dialers/already_connected.go
generated
vendored
Normal file
26
vendor/github.com/digitalocean/go-libvirt/socket/dialers/already_connected.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
package dialers
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// AlreadyConnected implements a dialer interface for a connection that was
|
||||
// established prior to initializing the socket object. This exists solely
|
||||
// for backwards compatability with the previous implementation of Libvirt
|
||||
// that took an already established connection.
|
||||
type AlreadyConnected struct {
|
||||
c net.Conn
|
||||
}
|
||||
|
||||
// NewAlreadyConnected is a noop dialer to simply use a connection previously
|
||||
// established. This means any re-dial attempts simply won't work.
|
||||
func NewAlreadyConnected(c net.Conn) AlreadyConnected {
|
||||
return AlreadyConnected{c}
|
||||
}
|
||||
|
||||
// Dial just returns the connection previously established.
|
||||
// If at some point it is disconnected by the client, this obviously does *not*
|
||||
// re-dial and will simply return the already closed connection.
|
||||
func (a AlreadyConnected) Dial() (net.Conn, error) {
|
||||
return a.c, nil
|
||||
}
|
57
vendor/github.com/digitalocean/go-libvirt/socket/dialers/local.go
generated
vendored
Normal file
57
vendor/github.com/digitalocean/go-libvirt/socket/dialers/local.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
package dialers
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// defaultSocket specifies the default path to the libvirt unix socket.
|
||||
defaultSocket = "/var/run/libvirt/libvirt-sock"
|
||||
|
||||
// defaultLocalTimeout specifies the default libvirt dial timeout.
|
||||
defaultLocalTimeout = 15 * time.Second
|
||||
)
|
||||
|
||||
// Local implements connecting to a local libvirtd over the unix socket.
|
||||
type Local struct {
|
||||
timeout time.Duration
|
||||
socket string
|
||||
}
|
||||
|
||||
// LocalOption is a function for setting local socket options.
|
||||
type LocalOption func(*Local)
|
||||
|
||||
// WithLocalTimeout sets the dial timeout.
|
||||
func WithLocalTimeout(timeout time.Duration) LocalOption {
|
||||
return func(l *Local) {
|
||||
l.timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// WithSocket sets the path to the local libvirt socket.
|
||||
func WithSocket(socket string) LocalOption {
|
||||
return func(l *Local) {
|
||||
l.socket = socket
|
||||
}
|
||||
}
|
||||
|
||||
// NewLocal is a default dialer to simply connect to a locally running libvirt's
|
||||
// socket.
|
||||
func NewLocal(opts ...LocalOption) *Local {
|
||||
l := &Local{
|
||||
timeout: defaultLocalTimeout,
|
||||
socket: defaultSocket,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(l)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// Dial connects to a local socket
|
||||
func (l *Local) Dial() (net.Conn, error) {
|
||||
return net.DialTimeout("unix", l.socket, l.timeout)
|
||||
}
|
61
vendor/github.com/digitalocean/go-libvirt/socket/dialers/remote.go
generated
vendored
Normal file
61
vendor/github.com/digitalocean/go-libvirt/socket/dialers/remote.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
package dialers
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// defaultRemotePort specifies the default libvirtd port.
|
||||
defaultRemotePort = "16509"
|
||||
|
||||
// defaultRemoteTimeout specifies the default libvirt dial timeout.
|
||||
defaultRemoteTimeout = 20 * time.Second
|
||||
)
|
||||
|
||||
// Remote implements connecting to a remote server's libvirt using tcp
|
||||
type Remote struct {
|
||||
timeout time.Duration
|
||||
host, port string
|
||||
}
|
||||
|
||||
// RemoteOption is a function for setting remote dialer options.
|
||||
type RemoteOption func(*Remote)
|
||||
|
||||
// WithRemoteTimeout sets the dial timeout.
|
||||
func WithRemoteTimeout(timeout time.Duration) RemoteOption {
|
||||
return func(r *Remote) {
|
||||
r.timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// UsePort sets the port to dial for libirt on the target host server.
|
||||
func UsePort(port string) RemoteOption {
|
||||
return func(r *Remote) {
|
||||
r.port = port
|
||||
}
|
||||
}
|
||||
|
||||
// NewRemote is a dialer for connecting to libvirt running on another server.
|
||||
func NewRemote(hostAddr string, opts ...RemoteOption) *Remote {
|
||||
r := &Remote{
|
||||
timeout: defaultRemoteTimeout,
|
||||
host: hostAddr,
|
||||
port: defaultRemotePort,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(r)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Dial connects to libvirt running on another server.
|
||||
func (r *Remote) Dial() (net.Conn, error) {
|
||||
return net.DialTimeout(
|
||||
"tcp",
|
||||
net.JoinHostPort(r.host, r.port),
|
||||
r.timeout,
|
||||
)
|
||||
}
|
376
vendor/github.com/digitalocean/go-libvirt/socket/socket.go
generated
vendored
Normal file
376
vendor/github.com/digitalocean/go-libvirt/socket/socket.go
generated
vendored
Normal file
@ -0,0 +1,376 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/digitalocean/go-libvirt/internal/constants"
|
||||
)
|
||||
|
||||
const disconnectTimeout = 5 * time.Second
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
// Dialer is an interface for connecting to libvirt's underlying socket.
|
||||
type Dialer interface {
|
||||
Dial() (net.Conn, error)
|
||||
}
|
||||
|
||||
// Router is an interface used to route packets to the appropriate clients.
|
||||
type Router interface {
|
||||
Route(*Header, []byte)
|
||||
}
|
||||
|
||||
// Socket represents a libvirt Socket and its connection state
|
||||
type Socket struct {
|
||||
dialer Dialer
|
||||
router Router
|
||||
|
||||
conn net.Conn
|
||||
reader *bufio.Reader
|
||||
writer *bufio.Writer
|
||||
// used to serialize any Socket writes and any updates to conn, r, or w
|
||||
mu *sync.Mutex
|
||||
|
||||
// disconnected is closed when the listen goroutine associated with a
|
||||
// Socket connection has returned.
|
||||
disconnected chan struct{}
|
||||
}
|
||||
|
||||
// packet represents a RPC request or response.
|
||||
type packet struct {
|
||||
// Size of packet, in bytes, including length.
|
||||
// Len + Header + Payload
|
||||
Len uint32
|
||||
Header Header
|
||||
}
|
||||
|
||||
// Global packet instance, for use with unsafe.Sizeof()
|
||||
var _p packet
|
||||
|
||||
// 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 int32
|
||||
|
||||
// Request status, e.g., StatusOK
|
||||
Status uint32
|
||||
}
|
||||
|
||||
// New initializes a new type for managing the Socket.
|
||||
func New(dialer Dialer, router Router) *Socket {
|
||||
s := &Socket{
|
||||
dialer: dialer,
|
||||
router: router,
|
||||
disconnected: make(chan struct{}),
|
||||
mu: &sync.Mutex{},
|
||||
}
|
||||
|
||||
// we start with a closed channel since that indicates no connection
|
||||
close(s.disconnected)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Connect uses the dialer provided on creation to establish
|
||||
// underlying physical connection to the desired libvirt.
|
||||
func (s *Socket) Connect() error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if !s.isDisconnected() {
|
||||
return errors.New("already connected to socket")
|
||||
}
|
||||
conn, err := s.dialer.Dial()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.conn = conn
|
||||
s.reader = bufio.NewReader(conn)
|
||||
s.writer = bufio.NewWriter(conn)
|
||||
s.disconnected = make(chan struct{})
|
||||
|
||||
go s.listenAndRoute()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Disconnect closes the Socket connection to libvirt and waits for the reader
|
||||
// gorouting to shut down.
|
||||
func (s *Socket) Disconnect() error {
|
||||
// just return if we're already disconnected
|
||||
if s.isDisconnected() {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := s.conn.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// now we wait for the reader to return so as not to avoid it nil
|
||||
// referencing
|
||||
// Put this in a select,
|
||||
// and have it only nil out the conn value if it doesn't fail
|
||||
select {
|
||||
case <-s.disconnected:
|
||||
case <-time.After(disconnectTimeout):
|
||||
return errors.New("timed out waiting for Disconnect cleanup")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Disconnected returns a channel that will be closed once the current
|
||||
// connection is closed. This can happen due to an explicit call to Disconnect
|
||||
// from the client, or due to non-temporary Read or Write errors encountered.
|
||||
func (s *Socket) Disconnected() <-chan struct{} {
|
||||
return s.disconnected
|
||||
}
|
||||
|
||||
// isDisconnected is a non-blocking function to query whether a connection
|
||||
// is disconnected or not.
|
||||
func (s *Socket) isDisconnected() bool {
|
||||
select {
|
||||
case <-s.disconnected:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// listenAndRoute reads packets from the Socket and calls the provided
|
||||
// Router function to route them
|
||||
func (s *Socket) listenAndRoute() {
|
||||
// only returns once it detects a non-temporary error related to the
|
||||
// underlying connection
|
||||
listen(s.reader, s.router)
|
||||
|
||||
// signal any clients listening that the connection has been disconnected
|
||||
close(s.disconnected)
|
||||
}
|
||||
|
||||
// listen processes incoming data and routes
|
||||
// responses to their respective callback handler.
|
||||
func listen(s io.Reader, router Router) {
|
||||
for {
|
||||
// response packet length
|
||||
length, err := pktlen(s)
|
||||
if err != nil {
|
||||
if isTemporary(err) {
|
||||
continue
|
||||
}
|
||||
// connection is no longer valid, so shutdown
|
||||
return
|
||||
}
|
||||
|
||||
// response header
|
||||
h, err := extractHeader(s)
|
||||
if err != nil {
|
||||
// invalid packet
|
||||
continue
|
||||
}
|
||||
|
||||
// payload: packet length minus what was previously read
|
||||
size := int(length) - int(unsafe.Sizeof(_p))
|
||||
buf := make([]byte, size)
|
||||
_, err = io.ReadFull(s, buf)
|
||||
if err != nil {
|
||||
// invalid packet
|
||||
continue
|
||||
}
|
||||
|
||||
// route response to caller
|
||||
router.Route(h, buf)
|
||||
}
|
||||
}
|
||||
|
||||
// isTemporary returns true if the error returned from a read is transient.
|
||||
// If the error type is an OpError, check whether the net connection
|
||||
// error condition is temporary (which means we can keep using the
|
||||
// connection).
|
||||
// Errors not of the net.OpError type tend to be things like io.EOF,
|
||||
// syscall.EINVAL, or io.ErrClosedPipe (i.e. all things that
|
||||
// indicate the connection in use is no longer valid.)
|
||||
func isTemporary(err error) bool {
|
||||
opErr, ok := err.(*net.OpError)
|
||||
if ok {
|
||||
return opErr.Temporary()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// pktlen returns the length of an incoming RPC packet. Read errors will
|
||||
// result in a returned response length of 0 and a non-nil error.
|
||||
func pktlen(r io.Reader) (uint32, error) {
|
||||
buf := make([]byte, unsafe.Sizeof(_p.Len))
|
||||
|
||||
// extract the packet's length from the header
|
||||
_, err := io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
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, unsafe.Sizeof(_p.Header))
|
||||
|
||||
// extract the packet's header from r
|
||||
_, err := io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &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: int32(binary.BigEndian.Uint32(buf[16:20])),
|
||||
Status: binary.BigEndian.Uint32(buf[20:24]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SendPacket sends a packet to libvirt on the socket connection.
|
||||
func (s *Socket) SendPacket(
|
||||
serial int32,
|
||||
proc uint32,
|
||||
program uint32,
|
||||
payload []byte,
|
||||
typ uint32,
|
||||
status uint32,
|
||||
) error {
|
||||
p := packet{
|
||||
Header: Header{
|
||||
Program: program,
|
||||
Version: constants.ProtocolVersion,
|
||||
Procedure: proc,
|
||||
Type: typ,
|
||||
Serial: serial,
|
||||
Status: status,
|
||||
},
|
||||
}
|
||||
|
||||
size := int(unsafe.Sizeof(p.Len)) + int(unsafe.Sizeof(p.Header))
|
||||
if payload != nil {
|
||||
size += len(payload)
|
||||
}
|
||||
p.Len = uint32(size)
|
||||
|
||||
if s.isDisconnected() {
|
||||
// this mirrors what a lot of net code return on use of a no
|
||||
// longer valid connection
|
||||
return syscall.EINVAL
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
err := binary.Write(s.writer, binary.BigEndian, p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// write payload
|
||||
if payload != nil {
|
||||
err = binary.Write(s.writer, binary.BigEndian, payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return s.writer.Flush()
|
||||
}
|
||||
|
||||
// SendStream sends a stream of packets to libvirt on the socket connection.
|
||||
func (s *Socket) SendStream(serial int32, 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-unsafe.Sizeof(_p))
|
||||
for {
|
||||
select {
|
||||
case <-abort:
|
||||
return s.SendPacket(serial, proc, program, nil, Stream, StatusError)
|
||||
default:
|
||||
}
|
||||
n, err := stream.Read(buf)
|
||||
if n > 0 {
|
||||
err2 := s.SendPacket(serial, proc, program, buf[:n], Stream, StatusContinue)
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return s.SendPacket(serial, proc, program, nil, Stream, StatusOK)
|
||||
}
|
||||
// keep original error
|
||||
err2 := s.SendPacket(serial, proc, program, nil, Stream, StatusError)
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
@ -15,13 +15,13 @@
|
||||
// This module provides different units of measurement to make other
|
||||
// code more readable.
|
||||
|
||||
package libvirt
|
||||
package socket
|
||||
|
||||
const (
|
||||
// B - byte
|
||||
B = 1
|
||||
// KiB - kibibyte
|
||||
// B - byte
|
||||
B = 1
|
||||
// KiB - kibibyte
|
||||
KiB = 1024 * B
|
||||
// MiB - mebibyte
|
||||
// MiB - mebibyte
|
||||
MiB = 1024 * KiB
|
||||
)
|
2
vendor/github.com/digitalocean/go-qemu/qmp/rpc.go
generated
vendored
2
vendor/github.com/digitalocean/go-qemu/qmp/rpc.go
generated
vendored
@ -67,11 +67,11 @@ func (rpc *LibvirtRPCMonitor) Events(ctx context.Context) (<-chan Event, error)
|
||||
|
||||
c := make(chan Event)
|
||||
go func() {
|
||||
defer close(c)
|
||||
// process events
|
||||
for e := range events {
|
||||
qe, err := qmpEvent(&e)
|
||||
if err != nil {
|
||||
close(c)
|
||||
break
|
||||
}
|
||||
|
||||
|
3
vendor/github.com/digitalocean/go-qemu/qmp/socket.go
generated
vendored
3
vendor/github.com/digitalocean/go-qemu/qmp/socket.go
generated
vendored
@ -104,6 +104,9 @@ func (mon *SocketMonitor) Disconnect() error {
|
||||
atomic.StoreInt32(mon.listeners, 0)
|
||||
err := mon.c.Close()
|
||||
|
||||
for range mon.stream {
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
10
vendor/modules.txt
vendored
10
vendor/modules.txt
vendored
@ -365,14 +365,16 @@ github.com/cyphar/filepath-securejoin
|
||||
# github.com/davecgh/go-spew v1.1.1
|
||||
## explicit
|
||||
github.com/davecgh/go-spew/spew
|
||||
# github.com/digitalocean/go-libvirt v0.0.0-20201209184759-e2a69bcd5bd1
|
||||
## explicit; go 1.14
|
||||
# github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e
|
||||
## explicit; go 1.15
|
||||
github.com/digitalocean/go-libvirt
|
||||
github.com/digitalocean/go-libvirt/internal/constants
|
||||
github.com/digitalocean/go-libvirt/internal/event
|
||||
github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2
|
||||
# github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001
|
||||
## explicit; go 1.15
|
||||
github.com/digitalocean/go-libvirt/socket
|
||||
github.com/digitalocean/go-libvirt/socket/dialers
|
||||
# github.com/digitalocean/go-qemu v0.0.0-20221209210016-f035778c97f7
|
||||
## explicit; go 1.18
|
||||
github.com/digitalocean/go-qemu/qmp
|
||||
# github.com/disiqueira/gotree/v3 v3.0.2
|
||||
## explicit; go 1.13
|
||||
|
Reference in New Issue
Block a user